Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

Motivation

A variety of different sources contribute different types of pollutants to what we call air pollution. Some sources are natural while others are anthropogenic (human derived):

[source]

Major types of air pollutants

  1. Gaseous - Carbon Monoxide (CO), Ozone (O3), Nitrogen Oxides(NO, NO2), Sulpher Dioxide (SO2)
  2. Particulate - small liquids and solids suspended in the air (includes lead- can include certain types of dust)
  3. Dust - small solids (larger than particulates) that can be suspended in the air for some time but eventually settle
  4. Biological - pollen, bacteria, viruses, mold spores

See [here])http://www.redlogenv.com/worker-safety/part-1-dust-and-particulate-matter) for more detail on the types of pollutants in the air.

Particulate pollution

Air pollution particulates are generally described by their size.

There are 3 major categories:

  1. Large Coarse Particulate Mater - has diameter of >10 micrometers (10 µm)

  2. Coarse Particulate Mater (called PM10-2.5) - has diameter of between 2.5 µm and 10 µm

  3. Fine Particulate Mater (called PM2.5) - has diameter of < 2.5 µm

PM10 includes any particulate mater <10 µm (both coarse and fine particulate mater)

Here you can see how these sizes compare with a human hair:

[source]

The following plot and table show the relative sizes of these different pollutants in micrometers(µm):

[source]

[source]

This table shows how deeply some of the smaller fine particles can penetrate within the human body:

[source]

Negative Impact of Particulate Exposure on Health

Exposure to air pollution is associated with higher rates of mortality in older adults and is known to be a risk factor for many diseases and conditions including but not limited to:

  1. Asthma - fine particle exposure (PM2.5) was found to be associated with higher rates of asthma in children
  2. Inflammation in type 1 diabetes - fine particle exposure (PM2.5) from traffic-related air pollution was associated with increased measures of inflammatory markers in youths with type 1 diabetes
  3. Lung function and emphysema - higher concentrations of ozone (O3), nitrogen oxides (NOx), black carbon, and fine particle exposure PM2.5 , at study baseline were significantly associated with greater increases in percent emphysema per 10 years
  4. Low birthweight - fine particle exposure(PM2.5) was associated with lower birth weight in full-term live births
  5. Viral Infection - higher rates of infection and increased severity of infection are associated with higher exposures to pollution levels including fine particle exposure (PM2.5)

See this review article for more information about sources of air pollution and the influence of air pollution on health.

Sparse Monitoring is Problematic for Public Health

Historically epidemiological studies would assess the influence of air pollution on health outcomes by relying on a number of monitors located around the country. However as can be seen in the following figure, these monitors remain to be relatively sparse in certain regions of the country. Furthermore, dramatic differences in pollution rates can be seen even within the same city.

[source]

This lack of granularity in air pollution monitoring has hindered our ability to discern the full impact of air pollution on health and to identify at-risk locations.

Machine Learning Offers a Solution

An article published in the Environmental Health journal dealt with this issue by using data about population density, road density, among other features to model or predict air pollution levels at a more localized scale using machine learning methods.

Yanosky, J. D. et al. Spatio-temporal modeling of particulate air pollution in the conterminous United States using geographic and meteorological predictors. Environ Health 13, 63 (2014).

The authors of this article state that:

“Exposure to atmospheric particulate matter (PM) remains an important public health concern, although it remains difficult to quantify accurately across large geographic areas with sufficiently high spatial resolution. Recent epidemiologic analyses have demonstrated the importance of spatially- and temporally-resolved exposure estimates, which show larger PM-mediated health effects as compared to nearest monitor or county-specific ambient concentrations.”

The article above explains that machine learning methods can be used to predict air pollution levels when traditional monitoring systems are not available in a particular area or when there is not enough spatial granularity with current monitoring systems. We will use similar methods to predict annual air pollution levels spatially within the US.

Main Questions

Our main question:

  1. Can we predict annual average air pollution concentrations at the granularity of zip code regional levels using predictors such as data about population density, urbanization, road density, as well as, satellite pollution data and chemical modeling data?

Learning Objectives

In this case study, we will walk you through importing data from CSV files and performing machine learning methods to predict our outcome variable of interest (in this case annual fine particle air pollution estimates). We will especially focus on using packages and functions from the Tidyverse, and more specifically the tidymodels package/ecosystem primarily developed and maintained by Max Kuhn and Davis Vaughan. This package loads more modeling related packages like rsample, recipes, parsnip, yardstick, and dials. We will also briefly cover the workflows and tune packages. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R especially efficient.

We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
readr to import the CSV file data
dplyr to view/arrange/filter/select/compare specific subsets of the data
skimr to get an overview of data
summarytools to get an overview of data in a different style
magrittr to use the %<>% pipping operator
GGally to create correlation plots
rsample to split the data into testing and training sets and to split the training set for cross-validation
recipes to pre-process data for modeling in a tidy and reproducible way and to extract pre-processed data (major functions are recipe() , prep() and various transformation step_*() functions, as well as juice() - extracts final preprocessed training data and bake() - applies recipe steps to testing data). See here for more info.
parsnip an interface to create models (major functions are fit(), set_engine())
yardstick to evaluate the performance of models

stringr | to manipulate the text within the PDF of the data

purrr | to perform functions on all columns of a tibble tibble | to create data objects that we can manipulate with dplyr/stringr/tidyr/purrr tidyr | to separate data within a column into multiple columns ggplot2 | to make visualizations with multiple layers ggpubr | to easily add regression line equations to plots forcats | to change details about factors (categorical variables) lmerTest| to perform linear mixed model testing car| to perform Levene’s Test of Homogeneity of Variances ggiraph| to make plots interactive ggforce| to modify facets in plots viridis| to plot in color palette that is easily interpreted by colorblind individuals cowplot | to allow plots to be combined ___

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context

The State of Global Air is a report released every year to communicate the impact of air pollution on public health.

The State of Global Air 2019 report which uses data from 2017 stated that:

Air pollution is the fifth leading risk factor for mortality worldwide. It is responsible for more deaths than many better-known risk factors such as malnutrition, alcohol use, and physical inactivity. Each year, more people die from air pollution–related disease than from road traffic injuries or malaria.

The report also stated that:

In 2017, air pollution is estimated to have contributed to close to 5 million deaths globally — nearly 1 in every 10 deaths.

##### [source]

The State of Global Air 2018 report using data from 2016 which separated different types of air pollution, found that particulate pollution was particularly associated with mortality.

The 2019 report shows that the highest levels of fine particulate pollution occurs in Africa and Asia and that:

More than 90% of people worldwide live in areas exceeding the World Health Organization (WHO) Guideline for healthy air. More than half live in areas that do not even meet WHO’s least-stringent air quality target.

Looking at the US specifically, air pollution levels are generally improving. The US Environmental Protection Agency (EPA) also releases a report about air pollution levels called Our Nation’s Air.

[source]

However, air pollution continues to contribute to health risk for Americans, in particular in regions with higher than national average rates of pollution that actually at time exceed the world health organization’s recommended level. Thus it is necessary to obtain high spatial granularity in estimates of air pollution in order to identify locations where populations are experiencing harmful levels of exposure.

You can see that current air quality conditions at this website and you will notice variation across different cities.

Here were the conditions in Topeka Kansas when this was written:

It reports particulate values using what is called the Air Quality Index scale (AQI), this calculator indicates that 114 AQI is equivalent to 40.7 ug/m3 and is considered unhealthy for sensitive individuals. Thus some areas very much exceed the World Health Organization (WHO) annual exposure guideline (10 ug/m3) at certain times and this may adversely affect the health of people living in these locations.

Furthermore, adverse health effects have been associated with populations experiencing higher pollution exposure despite the levels being below suggested guidelines. Secondly, it appears that the composition of the particulate mater and the influence of other demographic factors may make specific populations more at risk for adverse health effects due to air pollution. See this article for more details.

The monitor data that we will use in this case study comes from a system of monitors in which roughly 90% are located within cities. Thus there is an equity issue in terms of capturing the air pollution levels of more rural areas. Therefore, to get a better sense of the pollution exposures for the individuals living in these areas, methods like machine learning can be very useful to estimate air pollution levels in areas with little to no monitoring.

Indeed, machine learning methods are in fact used to be able to estimate air pollution in these low monitoring areas so that we can make a map like this where we have annual estimates for all of the contiguous US:

[source]

This is what we aim to achieve in this case study.

Limitations

There are some important considerations regarding this data analysis to keep in mind:

  1. The data in our analysis does not include information about the composition of particulate mater. Different types of particulates may be more benign or deleterious for health outcomes.

  2. Outdoor pollution levels are not necessarily an indication of of individual exposures. People spend differing amounts of time indoors and outdoors and are exposed to different pollution levels indoors. People are now developing personal monitoring systems to track air pollution levels on the personal level.

Our analysis will use annual mean estimates, however pollution levels can vary greatly by season, day and even hour. There are data sources that have finer levels of temporal data, however we are interested in long term exposures, as these appear to be the most influential for health outcomes, so we chose to use annual level data.

What are the data?

In Machine Learning for prediction, there are two main types of variables:

  1. Outcome variable
  2. Predictor variables

The outcome variable is what are trying to predict. In building our model we actually have the outcome variable data, but we want to see how well our predictor variables can explain the variation in our outcome data. This gives us a sense of how well we can use the predictor variable data to predict our outcome variable levels when we in fact do not have data about the outcome.

As a simpler example, imagine that we have data about the sales and characteristics of cars from last year and we want to predict which cars might sell well this year. We do not have the sales data yet for this year, but we do know the characteristics of our cars for this year. We can use a model of the characteristics that explained sales last year to estimate what cars might sell well this year. In this case, our outcome variable is the sale performance of the cars, while the different characteristics of the cars make up our predictor or explanatory variables.

In this case study, we will evaluate air pollution monitor data of fine particulate mater (PM2.5) in the contiguous US from 2008, as well as data about population density, road density, urbanization levels, and NASA satellite data to develop models to predict localized air pollution levels.

The monitor data will be our outcome variable. We want to determine if we can predict air pollution levels based on other types of data, like road density and population density to see if we can use these data to predict air pollution in areas where there are no monitors.

Our outcome variable

The monitor data that we will be using comes from gravimetric monitors operated by the US Enivornmental Protection Agency (EPA). These monitors use a filtration system to specifically capture fine particulate matter. The weight of this matter is manually measured daily or weekly. See here for the EPA standard operating procedure for PM gravimetric analysis in 2008.

[source]

Here is an image of what the gravimetric monitors look like:

Gravimetric analysis is also used for emission testing. The same idea applies: a fresh filter is applied and the desired amount of time passes, then the filter is removed and weighed.

There are other monitoring systems that can provide hourly measurements, but we will not be using data from these monitors in our analysis. Gravimetric analysis is considered to be among the most accurate methods.

In our csv, the value column indicates the PM2.5 monitor average for 2008 in mass of fine particles/volume of air for 876 gravimetric monitors. The units are micro grams of fine particulate mater (PM) that is less than 2.5 micrometers in diameter per cubic meter of air - mass concentration (ug/m3). Recall the the WHO exposure guideline is < 10 ug/m3 on average annually for PM2.5.

Our predictor variables

There are 48 predictor variables with values for each of the 876 monitors included in our outcome variable. The data comes from the US Enivornmental Protection Agency (EPA), the National Aeronautics and Space Administration (NASA), the US Census, and the National Center for Health Statistics (NCHS).

Variable Details
id Monitor number
– the county number is indicated before the decimal
– the monitor number is indicated after the decimal
Example: 1073.0023 is Jefferson county (1073) and .0023 one of 8 monitors
fips Federal information processing standard number for the county where the monitor is located
– 5 digit id code for counties (zero is often the first value and sometimes is not shown)
– the first 2 numbers indicate the state
– the last three numbers indicate the county
Example: Alabama’s state code is 01 because it is first alphabetically
(note: Alaska and Hawaii are not included because they are not part of the contiguous US)
Lat Latitude of the monitor in degrees
Lon Longitude of the monitor in degrees
state State where the monitor is located
county County where the monitor is located
city City where the monitor is located
CMAQ Estimated values of air pollution from a computational model called Community Multiscale Air Quality (CMAQ)
– A monitoring system that simulates the physics of the atmosphere using chemistry and weather data to predict the air pollution
Does not use any of the PM2.5 gravimetric monitoring data. (There is a version that does use the gravimetric monitoring data, but not this one!)
– Data from the EPA
zcta Zip Code Tabulation Area where the monitor is located
– Postal Zip codes are converted into “generalized areal representations” that are non-overlapping
– Data from the 2010 Census
zcta_area Land area of the zip code area in meters squared
– Data from the 2010 Census
zcta_pop Population in the zip code area
– Data from the 2010 Census
imp_a500 Impervious surface measure
– Within a circle with a radius of 500 meters around the monitor
– Impervious surface are roads, concrete, parking lots, buildings
– This is a measure of development
imp_a1000 Impervious surface measure
– Within a circle with a radius of 1000 meters around the monitor
imp_a5000 Impervious surface measure
– Within a circle with a radius of 5000 meters around the monitor
imp_a10000 Impervious surface measure
– Within a circle with a radius of 10000 meters around the monitor
imp_a15000 Impervious surface measure
– Within a circle with a radius of 15000 meters around the monitor
county_area Land area of the county of the monitor in meters squared
county_pop Population of the county of the monitor
Log_dist_to_prisec Log (Natural log) distance to a primary or secondary road from the monitor
– Highway or major road
log_pri_length_5000 Count of primary road length in meters in a circle with a radius of 5000 meters around the monitor (Natural log)
– Highways only
log_pri_length_10000 Count of primary road length in meters in a circle with a radius of 10000 meters around the monitor (Natural log)
– Highways only
log_pri_length_15000 Count of primary road length in meters in a circle with a radius of 15000 meters around the monitor (Natural log)
– Highways only
log_pri_length_25000 Count of primary road length in meters in a circle with a radius of 25000 meters around the monitor (Natural log)
– Highways only
log_prisec_length_500 Count of primary and secondary road length in meters in a circle with a radius of 500 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_1000 Count of primary and secondary road length in meters in a circle with a radius of 1000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_5000 Count of primary and secondary road length in meters in a circle with a radius of 5000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_10000 Count of primary and secondary road length in meters in a circle with a radius of 10000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_15000 Count of primary and secondary road length in meters in a circle with a radius of 15000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_25000 Count of primary and secondary road length in meters in a circle with a radius of 25000 meters around the monitor (Natural log)
– Highway and secondary roads
log_nei_2008_pm25_sum_10000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 10000 meters of distance around the monitor (Natural log)
log_nei_2008_pm25_sum_15000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 15000 meters of distance around the monitor (Natural log)
log_nei_2008_pm25_sum_25000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 25000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_10000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 10000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_15000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 15000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_25000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 25000 meters of distance around the monitor (Natural log)
popdens_county Population density (number of people per kilometer squared area of the county)
popdens_zcta Population density (number of people per kilometer squared area of zcta)
nohs Percentage of people in zcta area where the monitor is that do not have a high school degree
– Data from the Census
somehs Percentage of people in zcta area where the monitor whose highest formal educational attainment was some high school education
– Data from the Census
hs Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing a high school degree
– Data from the Census
somecollege Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing some college education
– Data from the Census
associate Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing an associate degree
– Data from the Census
bachelor Percentage of people in zcta area where the monitor whose highest formal educational attainment was a bachelor’s degree
– Data from the Census
grad Percentage of people in zcta area where the monitor whose highest formal educational attainment was a graduate degree
– Data from the Census
pov Percentage of people in zcta area where the monitor is that lived in poverty in 2008 - or would it have been 2007 guidelines??https://aspe.hhs.gov/2007-hhs-poverty-guidelines
– Data from the Census
hs_orless Percentage of people in zcta area where the monitor whose highest formal educational attainment was a high school degree or less (sum of nohs, somehs, and hs)
urc2013 2013 Urban-rural classification of the county where the monitor is located
– 6 category variable - 1 is totally urban 6 is completely rural
– Data from the National Center for Health Statistics](https://www.cdc.gov/nchs/index.htm){target="_blank"}
urc2006 2006 Urban-rural classification of the county where the monitor is located
– 6 category variable - 1 is totally urban 6 is completely rural
– Data from the National Center for Health Statistics
aod Aerosol Optical Depth measurement from a NASA satellite
– based on the defraction of a laser
– used as a proxy of particulate pollution
– unit-less - higher value indicates more pollution
– Data from NASA

Many of these predictor variables have to do with the circular area around the monitor called the “buffer”. These are illustrated in the following figure:

[source]

Data Import

We have one CSV file that contains both our single outcome variable and all of our predictor variables.

Let’s import our data into R now so that we can explore the data further. We will call our data object pm for particulate matter.

Data Exploration and Wrangling

The first step in performing a machine learning analysis is to explore the data to better understand the variables included in the data, as we may learn about important details about the data that we should keep in mind as we try to predict our outcome variable.

First let’s just get a general sense of our data. We can do that using the glimpse() function of the dplyr package (it is also in the tibble package).

We will also use the %>% pipe which can be used to define the input for later sequential steps. This will make more sense when we have multiple sequential steps using the same data object. To use the pipe notation we need to install and load dplyr as well.

For example here we will first grab the pm data object, then we use the glimpse() function on it based on the pipe notation.

Observations: 876
Variables: 50
$ id                          <dbl> 1003.001, 1027.000, 1033.100, 1049.1…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.6…
$ fips                        <dbl> 1003, 1027, 1033, 1049, 1055, 1069, …
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.287…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Al…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKal…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoal…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.5347…
$ zcta                        <dbl> 36532, 36251, 35660, 35962, 35901, 3…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 2038…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 3021…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038,…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.0…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.9…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, …
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430,…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.7214…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.5171…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409…
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.909…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.3101…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.5858…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.508…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.559…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.57312730…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.58191745…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.8876…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, …
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, …
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.1719…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.3…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 4…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 1…
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, …
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, …
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, …
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, …
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, …
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.083…

We can see that there are 876 monitors and that we have 50 total variables - one of which is the outcome. In this case our outcome variable is called value.

Notice that some of the variables that we would think of as factors (categorical) are currently of class double as indicated by the <dbl> just to the right of the column names/variable names in the glimpse() output. For example the monitor ID (id), the Federal Information Processing Standard number for the county where the monitor was located (fips), as well as the zcta

Let’s convert these variables into factors. We can do this using the mutate_at() function of the dplyr package and the as.factor() base function.

In this case we are also using the magrittr assignment pipe or double pipe that looks like this %<>% of the magrittr package. This allows us use the pm data as input but also reassign the output to the same data object name.

Observations: 876
Variables: 50
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1049…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.6…
$ fips                        <fct> 1003, 1027, 1033, 1049, 1055, 1069, …
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.287…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Al…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKal…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoal…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.5347…
$ zcta                        <fct> 36532, 36251, 35660, 35962, 35901, 3…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 2038…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 3021…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038,…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.0…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.9…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, …
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430,…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.7214…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.5171…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409…
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.909…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.3101…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.5858…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.508…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.559…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.57312730…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.58191745…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.8876…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, …
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, …
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.1719…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.3…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 4…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 1…
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, …
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, …
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, …
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, …
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, …
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.083…

Great! Now we can see that these variables are now factors as indicated by <fct> after the variable name.

The skim() function of the skimr package is also really helpful for getting a general sense of your data.

Data summary
Name pm
Number of rows 876
Number of columns 50
_______________________
Column type frequency:
character 3
factor 3
numeric 44
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
state 0 1 4 20 0 49 0
county 0 1 3 20 0 471 0
city 0 1 4 48 0 607 0

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
id 0 1 FALSE 876 100: 1, 102: 1, 103: 1, 104: 1
fips 0 1 FALSE 569 170: 12, 603: 10, 261: 9, 107: 8
zcta 0 1 FALSE 842 475: 3, 110: 2, 160: 2, 290: 2

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
value 0 1 10.81 2.580000e+00 3.02 9.27 11.15 12.37 2.316000e+01 ▂▆▇▁▁
lat 0 1 38.48 4.620000e+00 25.47 35.03 39.30 41.66 4.840000e+01 ▁▃▅▇▂
lon 0 1 -91.74 1.496000e+01 -124.18 -99.16 -87.47 -80.69 -6.804000e+01 ▃▂▃▇▃
CMAQ 0 1 8.41 2.970000e+00 1.63 6.53 8.62 10.24 2.313000e+01 ▃▇▃▁▁
zcta_area 0 1 183173481.91 5.425989e+08 15459.00 14204601.75 37653560.50 160041508.25 8.164821e+09 ▇▁▁▁▁
zcta_pop 0 1 24227.58 1.777216e+04 0.00 9797.00 22014.00 35004.75 9.539700e+04 ▇▇▃▁▁
imp_a500 0 1 24.72 1.934000e+01 0.00 3.70 25.12 40.22 6.961000e+01 ▇▅▆▃▂
imp_a1000 0 1 24.26 1.802000e+01 0.00 5.32 24.53 38.59 6.750000e+01 ▇▅▆▃▁
imp_a5000 0 1 19.93 1.472000e+01 0.05 6.79 19.07 30.11 7.460000e+01 ▇▆▃▁▁
imp_a10000 0 1 15.82 1.381000e+01 0.09 4.54 12.36 24.17 7.209000e+01 ▇▃▂▁▁
imp_a15000 0 1 13.43 1.312000e+01 0.11 3.24 9.67 20.55 7.110000e+01 ▇▃▁▁▁
county_area 0 1 3768701992.12 6.212830e+09 33703512.00 1116536297.50 1690826566.50 2878192209.00 5.194723e+10 ▇▁▁▁▁
county_pop 0 1 687298.44 1.293489e+06 783.00 100948.00 280730.50 743159.00 9.818605e+06 ▇▁▁▁▁
log_dist_to_prisec 0 1 6.19 1.410000e+00 -1.46 5.43 6.36 7.15 1.045000e+01 ▁▁▃▇▁
log_pri_length_5000 0 1 9.82 1.080000e+00 8.52 8.52 10.05 10.73 1.205000e+01 ▇▂▆▅▂
log_pri_length_10000 0 1 10.92 1.130000e+00 9.21 9.80 11.17 11.83 1.302000e+01 ▇▂▇▇▃
log_pri_length_15000 0 1 11.50 1.150000e+00 9.62 10.87 11.72 12.40 1.359000e+01 ▆▂▇▇▃
log_pri_length_25000 0 1 12.24 1.100000e+00 10.13 11.69 12.46 13.05 1.436000e+01 ▅▃▇▇▃
log_prisec_length_500 0 1 6.99 9.500000e-01 6.21 6.21 6.21 7.82 9.400000e+00 ▇▁▂▂▁
log_prisec_length_1000 0 1 8.56 7.900000e-01 7.60 7.60 8.66 9.20 1.047000e+01 ▇▅▆▃▁
log_prisec_length_5000 0 1 11.28 7.800000e-01 8.52 10.91 11.42 11.83 1.278000e+01 ▁▁▃▇▃
log_prisec_length_10000 0 1 12.41 7.300000e-01 9.21 11.99 12.53 12.94 1.385000e+01 ▁▁▃▇▅
log_prisec_length_15000 0 1 13.03 7.200000e-01 9.62 12.59 13.13 13.57 1.441000e+01 ▁▁▃▇▅
log_prisec_length_25000 0 1 13.82 7.000000e-01 10.13 13.38 13.92 14.35 1.523000e+01 ▁▁▃▇▆
log_nei_2008_pm25_sum_10000 0 1 3.97 2.350000e+00 0.00 2.15 4.29 5.69 9.120000e+00 ▆▅▇▆▂
log_nei_2008_pm25_sum_15000 0 1 4.72 2.250000e+00 0.00 3.47 5.00 6.35 9.420000e+00 ▃▃▇▇▂
log_nei_2008_pm25_sum_25000 0 1 5.67 2.110000e+00 0.00 4.66 5.91 7.28 9.650000e+00 ▂▂▇▇▃
log_nei_2008_pm10_sum_10000 0 1 4.35 2.320000e+00 0.00 2.69 4.62 6.07 9.340000e+00 ▅▅▇▇▂
log_nei_2008_pm10_sum_15000 0 1 5.10 2.180000e+00 0.00 3.87 5.39 6.72 9.710000e+00 ▂▃▇▇▂
log_nei_2008_pm10_sum_25000 0 1 6.07 2.010000e+00 0.00 5.10 6.37 7.52 9.880000e+00 ▁▂▆▇▃
popdens_county 0 1 551.76 1.711510e+03 0.26 40.77 156.67 510.81 2.682191e+04 ▇▁▁▁▁
popdens_zcta 0 1 1279.66 2.757490e+03 0.00 101.15 610.35 1382.52 3.041884e+04 ▇▁▁▁▁
nohs 0 1 6.99 7.210000e+00 0.00 2.70 5.10 8.80 1.000000e+02 ▇▁▁▁▁
somehs 0 1 10.17 6.200000e+00 0.00 5.90 9.40 13.90 7.220000e+01 ▇▂▁▁▁
hs 0 1 30.32 1.140000e+01 0.00 23.80 30.75 36.10 1.000000e+02 ▂▇▂▁▁
somecollege 0 1 21.58 8.600000e+00 0.00 17.50 21.30 24.70 1.000000e+02 ▆▇▁▁▁
associate 0 1 7.13 4.010000e+00 0.00 4.90 7.10 8.80 7.140000e+01 ▇▁▁▁▁
bachelor 0 1 14.90 9.710000e+00 0.00 8.80 12.95 19.22 1.000000e+02 ▇▂▁▁▁
grad 0 1 8.91 8.650000e+00 0.00 3.90 6.70 11.00 1.000000e+02 ▇▁▁▁▁
pov 0 1 14.95 1.133000e+01 0.00 6.50 12.10 21.22 6.590000e+01 ▇▅▂▁▁
hs_orless 0 1 47.48 1.675000e+01 0.00 37.92 48.65 59.10 1.000000e+02 ▁▃▇▃▁
urc2013 0 1 2.92 1.520000e+00 1.00 2.00 3.00 4.00 6.000000e+00 ▇▅▃▂▁
urc2006 0 1 2.97 1.520000e+00 1.00 2.00 3.00 4.00 6.000000e+00 ▇▅▃▂▁
aod 0 1 43.70 1.956000e+01 5.00 31.66 40.17 49.67 1.430000e+02 ▃▇▁▁▁

Notice how there is a column called n_missing about the number of values that are missing. It looks like our data is very complete and we do not have any missing data. This is also indicated by the complete_rate variable, which shows the ratio of completeness, in our case all variables have a value of 1 indicating they are fully complete.

The n_unqiue column shows us the number of unique values for each of our columns. We can see that there are 49 states represented in the data, and we know that the data should be of the contiguous states. Let’s take a look to see which states are included:

# A tibble: 49 x 1
   state               
   <chr>               
 1 Alabama             
 2 Arizona             
 3 Arkansas            
 4 California          
 5 Colorado            
 6 Connecticut         
 7 Delaware            
 8 District Of Columbia
 9 Florida             
10 Georgia             
11 Idaho               
12 Illinois            
13 Indiana             
14 Iowa                
15 Kansas              
16 Kentucky            
17 Louisiana           
18 Maine               
19 Maryland            
20 Massachusetts       
21 Michigan            
22 Minnesota           
23 Mississippi         
24 Missouri            
25 Montana             
26 Nebraska            
27 Nevada              
28 New Hampshire       
29 New Jersey          
30 New Mexico          
31 New York            
32 North Carolina      
33 North Dakota        
34 Ohio                
35 Oklahoma            
36 Oregon              
37 Pennsylvania        
38 Rhode Island        
39 South Carolina      
40 South Dakota        
41 Tennessee           
42 Texas               
43 Utah                
44 Vermont             
45 Virginia            
46 Washington          
47 West Virginia       
48 Wisconsin           
49 Wyoming             

Looks like “District of Columbia” is being included as a state. We can see that indeed Alaska and Hawaii are not included in the data.

Here is another method of looking at the data using the dfSummary() function of the summarytoolspackage. We need to copy and paste the output into the rmarkdown.

Dimensions: 876 x 50
Duplicates: 0

No Variable Stats / Values Freqs (% of Valid) Graph Valid Missing
1 id
[factor]
1. 1003.001
2. 1027.0001
3. 1033.1002
4. 1049.1003
5. 1055.001
6. 1069.0003
7. 1073.0023
8. 1073.1005
9. 1073.1009
10. 1073.101
[ 866 others ]
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
866 (98.9%)
876
(100%)
0
(0%)
2 value
[numeric]
Mean (sd) : 10.8 (2.6)
min < med < max:
3 < 11.2 < 23.2
IQR (CV) : 3.1 (0.2)
875 distinct values 876
(100%)
0
(0%)
3 fips
[factor]
1. 1003
2. 1027
3. 1033
4. 1049
5. 1055
6. 1069
7. 1073
8. 1089
9. 1097
10. 1101
[ 559 others ]
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
8 ( 0.9%)
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
858 (98.0%)
876
(100%)
0
(0%)
4 lat
[numeric]
Mean (sd) : 38.5 (4.6)
min < med < max:
25.5 < 39.3 < 48.4
IQR (CV) : 6.6 (0.1)
876 distinct values 876
(100%)
0
(0%)
5 lon
[numeric]
Mean (sd) : -91.7 (15)
min < med < max:
-124.2 < -87.5 < -68
IQR (CV) : 18.5 (-0.2)
876 distinct values 876
(100%)
0
(0%)
6 state
[character]
1. California
2. Ohio
3. Illinois
4. Indiana
5. North Carolina
6. Pennsylvania
7. Michigan
8. Florida
9. Georgia
10. Texas
[ 39 others ]
85 ( 9.7%)
44 ( 5.0%)
38 ( 4.3%)
36 ( 4.1%)
35 ( 4.0%)
32 ( 3.7%)
30 ( 3.4%)
29 ( 3.3%)
28 ( 3.2%)
27 ( 3.1%)
492 (56.2%)
876
(100%)
0
(0%)
7 county
[character]
1. Jefferson
2. Cook
3. Hamilton
4. Lake
5. Los Angeles
6. Wayne
7. Washington
8. Cuyahoga
9. Jackson
10. Madison
[ 461 others ]
18 ( 2.1%)
12 ( 1.4%)
11 ( 1.3%)
11 ( 1.3%)
10 ( 1.1%)
10 ( 1.1%)
9 ( 1.0%)
7 ( 0.8%)
7 ( 0.8%)
7 ( 0.8%)
774 (88.4%)
876
(100%)
0
(0%)
8 city
[character]
1. Not in a city
2. New York
3. Cleveland
4. Baltimore
5. Chicago
6. Detroit
7. Milwaukee
8. New Haven
9. Philadelphia
10. Springfield
[ 597 others ]
103 (11.8%)
9 ( 1.0%)
6 ( 0.7%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
723 (82.5%)
876
(100%)
0
(0%)
9 CMAQ  | Me [numeric] an (sd) : 8.4 (3)  | 60 min < med < max:
1.6 < 8.6 < 23.1
IQR (CV) : 3.7 (0.4)
1 distinct values | ![ ](tmp/ds0109.png) | 87 6  | 0
(100%)
(0%)
10 zcta
[factor]
1. 1022
2. 1103
3. 1201
4. 1608
5. 1832
6. 1840
7. 1863
8. 1904
9. 2113
10. 2119
[ 832 others ]
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
864 (98.6%)
876
(100%)
0
(0%)
11 zcta_area
[numeric]
Mean (sd) : 183173481.9 (542598878.5)
min < med < max:
15459 < 37653560.5 < 8164820625
IQR (CV) : 145836906.5 (3)
842 distinct values 876
(100%)
0
(0%)
12 zcta_pop
[numeric]
Mean (sd) : 24227.6 (17772.2)
min < med < max:
0 < 22014 < 95397
IQR (CV) : 25207.8 (0.7)
837 distinct values 876
(100%)
0
(0%)
13 imp_a500
[numeric]
Mean (sd) : 24.7 (19.3)
min < med < max:
0 < 25.1 < 69.6
IQR (CV) : 36.5 (0.8)
816 distinct values 876
(100%)
0
(0%)
14 imp_a1000
[numeric]
Mean (sd) : 24.3 (18)
min < med < max:
0 < 24.5 < 67.5
IQR (CV) : 33.3 (0.7)
860 distinct values 876
(100%)
0
(0%)
15 imp_a5000
[numeric]
Mean (sd) : 19.9 (14.7)
min < med < max:
0.1 < 19.1 < 74.6
IQR (CV) : 23.3 (0.7)
870 distinct values 876
(100%)
0
(0%)
16 imp_a10000
[numeric]
Mean (sd) : 15.8 (13.8)
min < med < max:
0.1 < 12.4 < 72.1
IQR (CV) : 19.6 (0.9)
870 distinct values 876
(100%)
0
(0%)
17 imp_a15000
[numeric]
Mean (sd) : 13.4 (13.1)
min < med < max:
0.1 < 9.7 < 71.1
IQR (CV) : 17.3 (1)
870 distinct values 876
(100%)
0
(0%)
18 county_area
[numeric]
Mean (sd) : 3768701992.1 (6212829553.6)
min < med < max:
33703512 < 1690826566.5 < 51947229509
IQR (CV) : 1761655911.5 (1.6)
564 distinct values 876
(100%)
0
(0%)
19 county_pop
[numeric]
Mean (sd) : 687298.4 (1293488.7)
min < med < max:
783 < 280730.5 < 9818605
IQR (CV) : 642211 (1.9)
564 distinct values 876
(100%)
0
(0%)
20 log_dist_to_prisec
[numeric]
Mean (sd) : 6.2 (1.4)
min < med < max:
-1.5 < 6.4 < 10.5
IQR (CV) : 1.7 (0.2)
870 distinct values 876
(100%)
0
(0%)
21 log_pri_length_5000
[numeric]
Mean (sd) : 9.8 (1.1)
min < med < max:
8.5 < 10.1 < 12
IQR (CV) : 2.2 (0.1)
586 distinct values 876
(100%)
0
(0%)
22 log_pri_length_10000
[numeric]
Mean (sd) : 10.9 (1.1)
min < med < max:
9.2 < 11.2 < 13
IQR (CV) : 2 (0.1)
687 distinct values 876
(100%)
0
(0%)
23 log_pri_length_15000
[numeric]
Mean (sd) : 11.5 (1.1)
min < med < max:
9.6 < 11.7 < 13.6
IQR (CV) : 1.5 (0.1)
726 distinct values 876
(100%)
0
(0%)
24 log_pri_length_25000
[numeric]
Mean (sd) : 12.2 (1.1)
min < med < max:
10.1 < 12.5 < 14.4
IQR (CV) : 1.4 (0.1)
787 distinct values 876
(100%)
0
(0%)
25 log_prisec_length_500
[numeric]
Mean (sd) : 7 (1)
min < med < max:
6.2 < 6.2 < 9.4
IQR (CV) : 1.6 (0.1)
382 distinct values 876
(100%)
0
(0%)
26 log_prisec_length_1000
[numeric]
Mean (sd) : 8.6 (0.8)
min < med < max:
7.6 < 8.7 < 10.5
IQR (CV) : 1.6 (0.1)
591 distinct values 876
(100%)
0
(0%)
27 log_prisec_length_5000
[numeric]
Mean (sd) : 11.3 (0.8)
min < med < max:
8.5 < 11.4 < 12.8
IQR (CV) : 0.9 (0.1)
852 distinct values 876
(100%)
0
(0%)
28 log_prisec_length_10000
[numeric]
Mean (sd) : 12.4 (0.7)
min < med < max:
9.2 < 12.5 < 13.8
IQR (CV) : 1 (0.1)
867 distinct values 876
(100%)
0
(0%)
29 log_prisec_length_15000
[numeric]
Mean (sd) : 13 (0.7)
min < med < max:
9.6 < 13.1 < 14.4
IQR (CV) : 1 (0.1)
869 distinct values 876
(100%)
0
(0%)
30 log_prisec_length_25000
[numeric]
Mean (sd) : 13.8 (0.7)
min < med < max:
10.1 < 13.9 < 15.2
IQR (CV) : 1 (0.1)
870 distinct values 876
(100%)
0
(0%)
31 log_nei_2008_pm25_sum_10000
[numeric]
Mean (sd) : 4 (2.4)
min < med < max:
0 < 4.3 < 9.1
IQR (CV) : 3.5 (0.6)
828 distinct values 876
(100%)
0
(0%)
32 log_nei_2008_pm25_sum_15000
[numeric]
Mean (sd) : 4.7 (2.2)
min < med < max:
0 < 5 < 9.4
IQR (CV) : 2.9 (0.5)
855 distinct values 876
(100%)
0
(0%)
33 log_nei_2008_pm25_sum_25000
[numeric]
Mean (sd) : 5.7 (2.1)
min < med < max:
0 < 5.9 < 9.7
IQR (CV) : 2.6 (0.4)
860 distinct values 876
(100%)
0
(0%)
34 log_nei_2008_pm10_sum_10000
[numeric]
Mean (sd) : 4.3 (2.3)
min < med < max:
0 < 4.6 < 9.3
IQR (CV) : 3.4 (0.5)
829 distinct values 876
(100%)
0
(0%)
35 log_nei_2008_pm10_sum_15000
[numeric]
Mean (sd) : 5.1 (2.2)
min < med < max:
0 < 5.4 < 9.7
IQR (CV) : 2.8 (0.4)
855 distinct values 876
(100%)
0
(0%)
36 log_nei_2008_pm10_sum_25000
[numeric]
Mean (sd) : 6.1 (2)
min < med < max:
0 < 6.4 < 9.9
IQR (CV) : 2.4 (0.3)
860 distinct values 876
(100%)
0
(0%)
37 popdens_county
[numeric]
Mean (sd) : 551.8 (1711.5)
min < med < max:
0.3 < 156.7 < 26821.9
IQR (CV) : 470 (3.1)
564 distinct values 876
(100%)
0
(0%)
38 popdens_zcta
[numeric]
Mean (sd) : 1279.7 (2757.5)
min < med < max:
0 < 610.3 < 30418.8
IQR (CV) : 1281.4 (2.2)
840 distinct values 876
(100%)
0
(0%)
39 nohs
[numeric]
Mean (sd) : 7 (7.2)
min < med < max:
0 < 5.1 < 100
IQR (CV) : 6.1 (1)
215 distinct values 876
(100%)
0
(0%)
40 somehs
[numeric]
Mean (sd) : 10.2 (6.2)
min < med < max:
0 < 9.4 < 72.2
IQR (CV) : 8 (0.6)
230 distinct values 876
(100%)
0
(0%)
41 hs
[numeric]
Mean (sd) : 30.3 (11.4)
min < med < max:
0 < 30.8 < 100
IQR (CV) : 12.3 (0.4)
347 distinct values 876
(100%)
0
(0%)
42 somecollege
[numeric]
Mean (sd) : 21.6 (8.6)
min < med < max:
0 < 21.3 < 100
IQR (CV) : 7.2 (0.4)
240 distinct values 876
(100%)
0
(0%)
43 associate
[numeric]
Mean (sd) : 7.1 (4)
min < med < max:
0 < 7.1 < 71.4
IQR (CV) : 3.9 (0.6)
157 distinct values 876
(100%)
0
(0%)
44 bachelor
[numeric]
Mean (sd) : 14.9 (9.7)
min < med < max:
0 < 12.9 < 100
IQR (CV) : 10.4 (0.7)
301 distinct values 876
(100%)
0
(0%)
45 grad
[numeric]
Mean (sd) : 8.9 (8.6)
min < med < max:
0 < 6.7 < 100
IQR (CV) : 7.1 (1)
245 distinct values 876
(100%)
0
(0%)
46 pov
[numeric]
Mean (sd) : 15 (11.3)
min < med < max:
0 < 12.1 < 65.9
IQR (CV) : 14.7 (0.8)
345 distinct values 876
(100%)
0
(0%)
47 hs_orless
[numeric]
Mean (sd) : 47.5 (16.8)
min < med < max:
0 < 48.7 < 100
IQR (CV) : 21.2 (0.4)
464 distinct values 876
(100%)
0
(0%)
48 urc2013
[numeric]
Mean (sd) : 2.9 (1.5)
min < med < max:
1 < 3 < 6
IQR (CV) : 2 (0.5)
1 : 203 (23.2%)
2 : 163 (18.6%)
3 : 228 (26.0%)
4 : 123 (14.0%)
5 : 101 (11.5%)
6 : 58 ( 6.6%)
876
(100%)
0
(0%)
49 urc2006
[numeric]
Mean (sd) : 3 (1.5)
min < med < max:
1 < 3 < 6
IQR (CV) : 2 (0.5)
1 : 195 (22.3%)
2 : 162 (18.5%)
3 : 221 (25.2%)
4 : 127 (14.5%)
5 : 115 (13.1%)
6 : 56 ( 6.4%)
876
(100%)
0
(0%)
50 aod
[numeric]
Mean (sd) : 43.7 (19.6)
min < med < max:
5 < 40.2 < 143
IQR (CV) : 18 (0.4)
581 distinct values 876
(100%)
0
(0%)

We can see that for many variables there are many low values as the distribution shows two peaks, one near zero and another with a higher value. This is true for the imp variables (measures of development), the nei variables (measures of emission sources) and the road density variables. We can also see that the range of some of the variables is very large, in particular the area and population related variables.

In prediction analyses, it is also useful to evaluate if any of the variables are correlated.

Intuitively we can expect some of our variables to be correlated.

We expect the development variables (imp) to be correlated with each other, we expect the road density variables to be correlated with each other, we expect the emission variables to be correlated with each other, and we also expect these variables to be correlated with one another and likely correlated with population density. We can get a nice visualization of correlation using the ggcorr() function and the ggpairs() function of the GGally package. to select our variables of interest we can use the select() function with the contains() function of the tidyr package.

First let’s look at the imp/development variables.

Indeed, we can see that imp_a1000 and imp_a500 are perfectly correlated, as well as imp_a10000, imp_a15000.

Now let’s take a look at the road density data:

We can see that while some of the road density variables are highly correlated with one another (or anti-correlated), there arr some variables that are less correlated with one another.

Finally let’s look at the emission variables.

We would also expect the population density data might correlate with some of these variables. Let’s take a look.

Interesting, so these variables don’t appear to be highly correlated, therefore we might need variables from each of the categories to predict our monitor PM2.5 pollution values.

We seem to have some pretty extreme population values though, so let’s see what happens when we take the log value.

Indeed this increased the correlation, but variables from each of these categories may still prove to be useful for prediction.

Data Analysis

Now that we have a sense of what our data is like we can get started with data analysis.

The tidymodels ecosystem

To perform our analysis we will be using the tidymodels suite of packages. You may be familiar with the older packages caret or mlr which are also for machine learning and modeling but are not a part of the tidyverse. Max Kuhn describes tidymodels like this:

“Other packages, such as caret and mlr, help to solve the R model API issue. These packages do a lot of other things too: preprocessing, model tuning, resampling, feature selection, ensembling, and so on. In the tidyverse, we strive to make our packages modular and parsnip is designed only to solve the interface issue. It is not designed to be a drop-in replacement for caret. The tidymodels package collection, which includes parsnip, has other packages for many of these tasks, and they are designed to work together. We are working towards higher-level APIs that can replicate and extend what the current model packages can do.”

The major benefits of tidymodels

  1. standardized workflow/format/notation across different types of algorithms
  2. can easily modify preprocessing, algorithm choice, and hyper-parameter tuning making optimization easy

The machine learning process

The tidymodels ecosystem - an overview

There are many packages in the tidymodels ecosystem which assist with the various steps of the machine learning process:

This is the overall process:

There are two distinct goals of supervised machine learning:

  1. Prediction
  2. Classification

We will be performing a prediction analysis (which is also refered to as regression), which aims to predict continuous outcome variables given a number of predictors/explanatory variables/features/parameters, as we have already described.

Classification on the other hand aims to discern or predict group identity for a categorical outcome based on a number of predictors/explanatory variables/features/parameters.

The overall process is the same in either case.

Splitting the Data

The first step after data exploration in machine learning analysis is to split the data into training and testing datasets.

The training dataset will be used to build and tune our model. This is the data that the model “learns” on.

The testing set will be used to evaluate the performance of our model in a more generalizable way. What do we mean by “generalizable”?

Remember that our main goal is to use our model to be able to predict air pollution levels in areas where there are no gravimetric monitors. Therefore, if our model is super good at predicting air pollution with the data that we use to build it, it might not do the best job for the areas where there are few to no monitors. This would cause us to have really good prediction accuracy and we might assume that we were going to do a good job estimating air pollution any time we use our model, but in fact this would likely not be the case. This situation is what we call overfitting .

Overfitting happens when we end up modeling not only the major relationships in our data but also the noise within our data.

[source]

If we get fairly good prediction with our testing set then we will know that our model can be applied to other data and will perform fairly well. We will discuss this more later.

We will not touch the testing set until we have completed optimizing our model with the training set. This will allow us to have a less biased evaluation of how well our model can do with other data besides the data used in the training set to build the model. Ideally you would also want a completely independent dataset to further test the performance of your model.

Here is a great description of the differences between testing and training datasets.

We will use the rsample package to perform this step.

Theinitial_split() function allows us to specify how we want to split our data. Typically data is split into 3/4 for training and 1/4 for testing.This is the default proportion and does not need to be specified. However you can change the proportion using the prop argument, which we will do that here for illustrative purposes. You can also specify a variable to stratify by with the strata argument. This is useful if you have imbalanced categorical variables and you would like to intentionally make sure that there are similar number of samples of the rarer categories in both the testing and training sets. Otherwise the split is performed randomly.

The strata argument causes the random sampling to be conducted within the stratification variable. The can help ensure that the number of data points in the training data is equivalent to the proportions in the original data set.

In the case with our dataset, perhaps we would like our training set to have similar proportions of monitors from each of the states as in the initial data. This might be useful if we want our model to be generalizable across all of the states.

We can see that indeed there are different proportions of monitors in each state by using the count() function of the dpyr package.

# A tibble: 49 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 24
 2 Arizona                 17
 3 Arkansas                16
 4 California              85
 5 Colorado                15
 6 Connecticut             14
 7 Delaware                 7
 8 District Of Columbia     3
 9 Florida                 29
10 Georgia                 28
11 Idaho                    7
12 Illinois                38
13 Indiana                 36
14 Iowa                    20
15 Kansas                  10
16 Kentucky                22
17 Louisiana               17
18 Maine                    1
19 Maryland                15
20 Massachusetts           16
21 Michigan                30
22 Minnesota               17
23 Mississippi             12
24 Missouri                13
25 Montana                 16
26 Nebraska                 7
27 Nevada                   4
28 New Hampshire            7
29 New Jersey              23
30 New Mexico              10
31 New York                24
32 North Carolina          35
33 North Dakota             4
34 Ohio                    44
35 Oklahoma                10
36 Oregon                  17
37 Pennsylvania            32
38 Rhode Island             5
39 South Carolina          14
40 South Dakota             9
41 Tennessee                3
42 Texas                   27
43 Utah                    14
44 Vermont                  4
45 Virginia                20
46 Washington               8
47 West Virginia           14
48 Wisconsin               21
49 Wyoming                 12

If our dataset were large enough it might be nice then to stratify by state, but our data is unfortunately not large enough. We will show how one would do this though for illustrative purposes. This option is often more important for classification applications of machine learning than it is for prediction.

Since the split is performed randomly, it is a good idea to use the set.seed() base function to ensure that if your rerun your code that your split will be the same next time. We can see the number of monitors in our training, testing, and original data by typing in the name of our split object. The result will look like this: <training data sample number, testing data sample number, original sample number>

<584/292/876>

Importantly the initial_split function only determines what rows of our pm data frame should be assigned for training or testing, it does not actually split the data.

To extract the testing and training data we can use the training() and testing() functions also of the rsample package.

# A tibble: 48 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 18
 2 Arizona                 12
 3 Arkansas                14
 4 California              54
 5 Colorado                12
 6 Connecticut              8
 7 Delaware                 6
 8 District Of Columbia     2
 9 Florida                 18
10 Georgia                 17
# … with 38 more rows
# A tibble: 48 x 2
   state                    n
   <chr>                <int>
 1 Alabama                  6
 2 Arizona                  5
 3 Arkansas                 2
 4 California              31
 5 Colorado                 3
 6 Connecticut              6
 7 Delaware                 1
 8 District Of Columbia     1
 9 Florida                 11
10 Georgia                 11
# … with 38 more rows

Variable Role Assignment and Preprocessing

In tidymodels we will create a recipe, which is a standardized format for a sequence of steps for processing the data.

This can be very useful because it makes testing out different pre-processing steps or different algorithms with the same pre-processing very easy and reproducible.

Creating a recipe specifies how a dataframe of predictors should be created - it specifies what variables to be used and the preprocessing steps but it does not execute these steps or create the dataframe of predictors.

List the ingredients / specify the variables with the recipe() function

The first thing to do to create a recipe is to specify which variables we will be using as our outcome and predictors using the recipe() function. In terms of the metaphor of baking, we can think of this as listing our ingredients. The naming convention for recipe object names is *_rec or rec.

In our case recall that our value variable, which is the average annual gravimetric monitor PM2.5 concentration in ug/m3. Our predictors are all the other variables except the monitor ID, which is an id variable.

The reason not to include this variable is because this variable includes the county number and a number designating which particular monitor the values came from of the monitors there are in that county. Since this number is arbitrary and the county information is also given in the data, and the fact that each monitor only has one value in the value variable, nothing is gained by including this variable and it may instead introduce noise. However, it is useful to keep this data to take a look at what is happening later. We will show you what to do in this case in just a bit.

The simplest recipe with no preprocessing steps, would be to simply list the outcome and predictor variables.

We can do so in two ways:

  1. Using formula notation
  2. Assigning roles to each variable

Let’s look at the first way using formula notation, which looks like this:

outcome(s) ~ predictor(s)

If in the case of multiple predictors or a multivariate situation with two outcomes, use a plus sign

outcome1 + outcome2 ~ predictor1 + predictor2

If we want to include all predictors we can use a period like so:

outcome_variable_name ~ .

Now with our data we will start by making a recipe for our training data. In the simplest case we might use all predictors like this:

Data Recipe

Inputs:

      role #variables
   outcome          1
 predictor         49

However, to deal with the id variable we could use the update_role() function of the recipes package:

Data Recipe

Inputs:

        role #variables
 id variable          1
     outcome          1
   predictor         48

We could also specify the outcome and predictors in the same way as the id variable. Please see here for examples of other roles for variables. The role can be actually be any value.

The order is important here, as we first make all variables predictors and then override this role for the outcome and id variable. We will use the everything() function of the dplyr package to start with all of the variables in train_pm.

Data Recipe

Inputs:

        role #variables
 id variable          1
     outcome          1
   predictor         48

If we want to take a look at our formula from our recipe we can do use the formula() function of the stats package.

value ~ fips + lat + lon + state + county + city + CMAQ + zcta + 
    zcta_area + zcta_pop + imp_a500 + imp_a1000 + imp_a5000 + 
    imp_a10000 + imp_a15000 + county_area + county_pop + log_dist_to_prisec + 
    log_pri_length_5000 + log_pri_length_10000 + log_pri_length_15000 + 
    log_pri_length_25000 + log_prisec_length_500 + log_prisec_length_1000 + 
    log_prisec_length_5000 + log_prisec_length_10000 + log_prisec_length_15000 + 
    log_prisec_length_25000 + log_nei_2008_pm25_sum_10000 + log_nei_2008_pm25_sum_15000 + 
    log_nei_2008_pm25_sum_25000 + log_nei_2008_pm10_sum_10000 + 
    log_nei_2008_pm10_sum_15000 + log_nei_2008_pm10_sum_25000 + 
    popdens_county + popdens_zcta + nohs + somehs + hs + somecollege + 
    associate + bachelor + grad + pov + hs_orless + urc2013 + 
    urc2006 + aod
<environment: 0x7fb3b4252040>

We can also view our recipe in more detail using the base summary() function.

# A tibble: 50 x 4
   variable type    role        source  
   <chr>    <chr>   <chr>       <chr>   
 1 id       nominal id variable original
 2 value    numeric outcome     original
 3 fips     nominal predictor   original
 4 lat      numeric predictor   original
 5 lon      numeric predictor   original
 6 state    nominal predictor   original
 7 county   nominal predictor   original
 8 city     nominal predictor   original
 9 CMAQ     numeric predictor   original
10 zcta     nominal predictor   original
# … with 40 more rows

List the preprocessing steps using the step functions of the recipe package

The other thing the recipes package allows for is specifying pre-processing steps using a variety of step*() functions.

This link and this link show the many options for recipe step functions.

There are step functions for a variety of purposes:

  1. Imputation – which means filling in missing values based on the existing data
  2. Transformation – which means changing all values of a variable in the same way, typically to make it more normal or easier to interpret)
  3. Discretization – which means converting continuous values into discrete or nominal values - binning for example to reduce the number of possible levels) (However this is generally not advisable!)
  4. Encoding / Creating Dummy Variables – which means creating a numeric code for categorical variables More on Dummy Variables and one hot encoding
  5. Data type conversions – which means changing from integer to factor or numeric to date etc.
  6. Interaction term addition to the model – which means that we would be modeling for predictors that would influence the capacity of each other to predict the outcome
  7. Normalization – which means centering and scaling the data to a similar range of values
  8. Dimensionality Reduction/ Signal Extraction – which means mathematically obtaining a new smaller set of variables that capture the variation or signal in the original variables (ex. Principal Component Analysis and Independent Component Analysis)
  9. Filtering – Filtering options for removing variables (ex. remove variables that are highly correlated to others or remove variables with very little variance and therefore likely little predictive capacity)
  10. Row operations – which means performing functions on the values within the rows (ex. rearranging, filtering, imputing)
  11. Checking functions – Sanity checks to look for missing values, to look at the variable classes etc.

All of the step functions look like step_* except for the check functions which look like check_*.

There are several ways to select what variables to apply steps to:
1) tidyselect methods: contains(), matches(), starts_with(), ends_with(), everything(), num_range()
2) based on the type: all_nominal(), all_numeric() , has_type() 3) based on the role: all_predictors(), all_outcomes(), has_role() 4) name - use the actual name of the variable/variables of interest

Let’s try adding some steps to our recipe.

We might consider log transforming our population and area variables (that aren’t densities) - let’s take a look at the range of these variables.

$zcta_area
[1]      15459 8164820625

$zcta_pop
[1]     0 95397

$county_area
[1]    33703512 51947229509

$county_pop
[1]     783 9818605

We can see that the range for each of these variables is quite large, we can log transform this data using the step_log() function of the recipes package.

We would also want to potentially one hot encode some of our categorical variables so that they can be used with certain algorithms. We can do this with the step_dummy() function and the one_hot = TRUE argument. Our fips variable includes a numeric code for state and county - and therefore is essentially a proxy for county. Since we already have county, we will just use it and keep the fips id as another ID variable.

We can remove the fips variable from the predictors using update_role() to make sure that the role is no longer "predictor". We can make the role anything we want actually, so we will keep it something identifiable.

We might also want to remove variables that appear to be redundant and are highly correlated with others, as we know from our exploratory data analysis that many of our variables are correlated with one another. We can do this using the step_corr() function.

It is important to add the steps to the recipe in an order that makes sense just like with a cooking recipe.

Data Recipe

Inputs:

        role #variables
   county id          1
 id variable          1
     outcome          1
   predictor         47

Operations:

Dummy variables from state, county, city, zcta
Correlation filter on all_numeric, -, CMAQ, -, aod
Sparse, unbalanced variable filter on all_numeric

OPTIONAL: Running the preprocessing (to see it)

The next major function of the recipes package is prep().

This function updates the recipe object based on the training data. It estimates parameters (estimating the required quantities and statistics required by the steps for the variables) for preprocessing and updates the model terms, as some of the predictors may be removed, this allows the recipe to be ready to use on other datasets. It doesn’t necessarily actually execute the preprocessing itself, however we will specify in argument for it to do this so that we can take a look at the preprocessed data.

There are some important arguments to know about: 1) training - you must supply a training data set to estimate parameters for preprocessing operations (recipe steps) - this may already be included in your recipe - as is the case for us 2) fresh - if TRUE - will retrain and estimate parameters for any previous steps that were already prepped if you add more steps to the recipe 3) verbose - if TRUE shows the progress as the steps are evaluated and the size of the preprocessed training set 4) retain - if TRUE then the preprocessed training set will be saved within the recipe (as template). This is good if you are likely to add more steps and don’t want to rerun the prep() on the previous steps. However this can make the recipe size large. This is necessary if you want to actually look at the preprocessed data.

oper 1 step dummy [training] 
oper 2 step corr [training] 
oper 3 step nzv [training] 
The retained training set is ~ 0.26 Mb  in memory.
[1] "var_info"       "term_info"      "steps"          "template"      
[5] "levels"         "retained"       "tr_info"        "orig_lvls"     
[9] "last_term_info"

There are also lots of useful things to checkout in the output of prep(). You can see: 1) the steps that were run
2) the variable info (var_info)
3) the model term_info 4) the new levels of the variables 5) the original levels of the variables orig_lvls
6) info about the training data set size and completeness (tr_info)

Note: You may see the prep.recipe() function in material that you read about the recipes package. This is referring to the prep() function of the recipes package.

Extracting the preprocessed training data

Since we retained our preprocessed training data, we can take a look at it like by using the juice() function of the recipes package like this:

Observations: 584
Variables: 36
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1055…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 12.3…
$ fips                        <fct> 1003, 1027, 1033, 1055, 1069, 1073, …
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 33.993…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 9.2417…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 1540…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 20045, 30217, 901…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038,…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 5.1…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, …
$ county_pop                  <dbl> 182265, 13932, 54428, 104430, 101547…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 5.2614…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 9.0665…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 12.013…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 8.7406…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 9.6278…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 11.…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 12.768…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, …
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 4.6783…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 75.3…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 1…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 4.3, 5.8, 7.1, 2.7, …
$ somehs                      <dbl> 4.9, 19.1, 15.8, 13.3, 11.6, 17.1, 6…
$ hs                          <dbl> 25.1, 33.9, 30.6, 27.8, 29.8, 37.2, …
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 29.2, 21.4, 23.5, …
$ associate                   <dbl> 8.2, 8.0, 7.6, 10.1, 7.9, 7.3, 8.0, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 10.0, 13.7, 5.9, 17…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.4, 9.8, 2.0, 8.7, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 8.8, 15.6, 25.5, 7.…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 45.4, 47.2, 61.4, …
$ urc2013                     <dbl> 4, 6, 4, 4, 4, 1, 1, 1, 1, 1, 2, 3, …
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 43.416…
$ state_California            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ city_Not.in.a.city          <dbl> 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, …

For easy comparison sake - here is our original data: #### {.scrollable }

Observations: 876
Variables: 50
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1049…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.6…
$ fips                        <fct> 1003, 1027, 1033, 1049, 1055, 1069, …
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.287…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Al…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKal…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoal…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.5347…
$ zcta                        <fct> 36532, 36251, 35660, 35962, 35901, 3…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 2038…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 3021…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038,…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.0…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.9…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, …
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430,…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.7214…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.5171…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409…
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.909…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.3101…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.5858…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.508…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.559…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.57312730…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.58191745…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.8876…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, …
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, …
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.1719…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.3…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 4…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 1…
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, …
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, …
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, …
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, …
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, …
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.083…

Notice how we only have 36 variables now instead of 50! Two of these are our ID variables (fips and the actual monitor ID (id)) and one is our outcome (value). Thus we only have 33 predictors now. We can also see that variables that we no longer have any categorical variables. Variables like state are gone and only state_California remains as it was the only state identity to have nonzero variance. We can see that California had the largest number of monitors compared to the other states. We can also see that there were more monitors listed as "Not in a city" than any city.

# A tibble: 49 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 24
 2 Arizona                 17
 3 Arkansas                16
 4 California              85
 5 Colorado                15
 6 Connecticut             14
 7 Delaware                 7
 8 District Of Columbia     3
 9 Florida                 29
10 Georgia                 28
# … with 39 more rows
# A tibble: 607 x 2
   city            n
   <chr>       <int>
 1 Aberdeen        1
 2 Akron           2
 3 Albany          3
 4 Albuquerque     2
 5 Alexandria      1
 6 Allen Park      1
 7 Altamont        1
 8 Alton           1
 9 Amarillo        1
10 Anadarko        1
# … with 597 more rows

Note: Recall that you must specify retain = TRUE argument of the prep() function to use juice().

Extracting the preprocessed testing data

Later on if you want to look at the preprocessed testing data you would use the bake() function of the recipes package like this:

However you would want to leave your testing data alone at this point.

Observations: 292
Variables: 36
$ id                          <fct> 1049.1003, 1073.101, 1073.2006, 1089…
$ value                       <dbl> 11.659091, 13.114545, 12.228125, 12.…
$ fips                        <fct> 1049, 1073, 1073, 1089, 1103, 1121, …
$ lat                         <dbl> 34.28763, 33.54528, 33.38639, 34.687…
$ lon                         <dbl> -85.96830, -86.54917, -86.81667, -86…
$ CMAQ                        <dbl> 8.534772, 9.303766, 10.235612, 9.343…
$ zcta_area                   <dbl> 203836235, 148994881, 56063756, 4696…
$ zcta_pop                    <dbl> 8300, 14212, 32390, 21297, 30545, 77…
$ imp_a500                    <dbl> 5.78200692, 0.06055363, 42.42820069,…
$ imp_a15000                  <dbl> 0.9730444, 2.9956557, 12.7487614, 10…
$ county_area                 <dbl> 2012662359, 2878192209, 2878192209, …
$ county_pop                  <dbl> 71109, 658466, 658466, 334811, 11949…
$ log_dist_to_prisec          <dbl> 3.721489, 7.301545, 4.721755, 4.6595…
$ log_pri_length_5000         <dbl> 8.517193, 9.683336, 10.737240, 8.517…
$ log_pri_length_25000        <dbl> 11.90959, 12.53777, 12.99669, 11.473…
$ log_prisec_length_500       <dbl> 7.310155, 6.214608, 7.528913, 8.7605…
$ log_prisec_length_1000      <dbl> 8.585843, 7.600902, 9.342290, 9.5431…
$ log_prisec_length_5000      <dbl> 10.214200, 11.262645, 11.713190, 11.…
$ log_prisec_length_10000     <dbl> 11.50894, 12.14101, 12.53899, 12.684…
$ log_nei_2008_pm10_sum_15000 <dbl> 3.3500444, 6.6241114, 5.8268686, 3.8…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.1719202, 7.5490587, 8.8205542, 5.2…
$ popdens_county              <dbl> 35.330814, 228.777633, 228.777633, 1…
$ popdens_zcta                <dbl> 40.718962, 95.385827, 577.735106, 45…
$ nohs                        <dbl> 14.3, 7.2, 0.8, 1.2, 4.8, 16.7, 19.1…
$ somehs                      <dbl> 16.7, 12.2, 2.6, 3.1, 7.8, 33.3, 15.…
$ hs                          <dbl> 35.0, 32.2, 12.9, 15.1, 28.7, 37.5, …
$ somecollege                 <dbl> 14.9, 19.0, 17.9, 20.5, 25.0, 12.5, …
$ associate                   <dbl> 5.5, 6.8, 5.2, 6.5, 7.5, 0.0, 6.0, 8…
$ bachelor                    <dbl> 7.9, 14.8, 35.5, 30.4, 18.2, 0.0, 10…
$ grad                        <dbl> 5.8, 7.7, 25.2, 23.3, 8.0, 0.0, 4.1,…
$ pov                         <dbl> 13.8, 10.5, 2.1, 5.2, 8.3, 18.8, 21.…
$ hs_orless                   <dbl> 66.0, 51.6, 16.3, 19.4, 41.3, 87.5, …
$ urc2013                     <dbl> 6, 1, 1, 3, 4, 5, 1, 2, 5, 4, 4, 6, …
$ aod                         <dbl> 33.08333, 42.45455, 44.25000, 42.416…
$ state_California            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ city_Not.in.a.city          <dbl> NA, NA, NA, NA, NA, NA, 0, NA, NA, N…

bake() takes a trained recipe and applies the operations to a data set to create a design matrix. for example: it applies the centering to new data sets using these means used to create the recipe

Note: if you use the skip option for some of the preprocessing steps, be careful. juice() will show all of the results ignoring skip = TRUE. bake() will not necessarily conduct these steps on the new data.

Specifying the Model

So far we have used rsample to split the data and recipes to assign variable and to specify and prep our preprocessing (as well as to optionally extract the preprocessed data).

We will now use the parsnip package (which is similar to the previous caret package - and hence why it is named after the vegetable) to specify our model.

There are four aspects to define about our model:
1) the type of model (using specific funtions in parsnip like rand_forest(), logistic_reg() etc.)
2) the mode of learning - classification or regression (using the set_mode() function)
3) the package or engine that we will use to implement the type of model selected (using the set_engine() function)
4) any arguments necessary for the model/package selected (using the set_args()function - for example the mtry = argument for random forest which is the number of variables to be used as options for splitting at each tree node)

We are going to start our analysis with a linear regression but we will demonstrate how we can try different models.

The first thing we do is define what type of model we would like to use. See here for modeling [options]in parsnip.

Linear Regression Model Specification (regression)

OK. So far all we have told parsnip is we want to use a linear regression… Let’s tell parsnip more about what we want.

We would like to use the ordinary least squares method to fit our linear regression. So we will tell parsnip that we want to use the lm package to implement our linear regression (there are many options actually- such as rstan glmnet, keras, and sparklyr). We will do so by using the set_engine() function of the parsnip package.

Linear Regression Model Specification (regression)

Computational engine: lm 

In some cases some packages can do either classification or prediction, so it is a good idea to specify which mode you intend to perform. You can do this with the set_mode() function of the parsnip package, by using either set_mode("classification") or set_mode("regression").

Linear Regression Model Specification (regression)

Computational engine: lm 

Fitting the Model with workflows and parsnip

To fit our model we could use parsnip and then assess our fit using the yardstick package.

However a newer package called workflows allows us to keep track of both our preprocessing steps and our model specification. It also allows us to implement fancier optimizations in an automated way and it is currently being developed to also handle post-processing operations, so it is good to learn about it!

So we will now create a workflow with the recipe (our preprocessing specifications) that we made and the model that we just specified.

First we use the workflow() function of the workflows package to create a workflow.

Then we add our recipe with the add_recipe() function and we add our model with the add_model() function of the workflows package.

Note: We do not need to actually prep our recipe before using workflows!

══ Workflow ═════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ─────────────────────────────────────────────────────────────────────────────
3 Recipe Steps

● step_dummy()
● step_corr()
● step_nzv()

── Model ────────────────────────────────────────────────────────────────────────────────────
Linear Regression Model Specification (regression)

Computational engine: lm 

Ah, nice. Notice how it tells us about both our preprocessing steps and our model specifications.

Now we can prepare the recipe (estimate the parameters) and fit the model to our training data all at once. Printing the output we can see the coefficients of the model.

══ Workflow [trained] ═══════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ─────────────────────────────────────────────────────────────────────────────
3 Recipe Steps

● step_dummy()
● step_corr()
● step_nzv()

── Model ────────────────────────────────────────────────────────────────────────────────────

Call:
stats::lm(formula = formula, data = data)

Coefficients:
                (Intercept)                          lat  
                  2.221e+02                    3.773e-02  
                        lon                         CMAQ  
                  3.023e-02                    2.896e-01  
                  zcta_area                     zcta_pop  
                  3.592e-10                    7.988e-06  
                   imp_a500                   imp_a15000  
                  6.543e-03                   -1.252e-03  
                county_area                   county_pop  
                 -2.241e-11                   -2.052e-07  
         log_dist_to_prisec          log_pri_length_5000  
                  4.182e-02                   -2.207e-01  
       log_pri_length_25000        log_prisec_length_500  
                  9.277e-02                    2.651e-01  
     log_prisec_length_1000       log_prisec_length_5000  
                 -1.654e-02                    4.451e-01  
    log_prisec_length_10000  log_nei_2008_pm10_sum_15000  
                  1.510e-01                    1.029e-01  
log_nei_2008_pm10_sum_25000               popdens_county  
                  6.448e-02                   -3.905e-05  
               popdens_zcta                         nohs  
                 -2.098e-05                   -2.195e+00  
                     somehs                           hs  
                 -2.232e+00                   -2.235e+00  
                somecollege                    associate  
                 -2.237e+00                   -2.237e+00  
                   bachelor                         grad  
                 -2.239e+00                   -2.248e+00  
                        pov                    hs_orless  
                  5.400e-03                           NA  
                    urc2013                          aod  
                  1.848e-01                    2.521e-02  
           state_California           city_Not.in.a.city  
                  3.509e+00                    4.137e-01  

Otherwise we could have done this without the workflows package. Notice here we will used the prepped training data as opposed to the raw training data that we used with the workflow we created with workflows.

Looking at model fit with broom

The broom package allows for an easy/tidy way to look at the fitted model:

tidy() grabs the coefficients from the model
glance() summarizes the model fit
augment() gives a 150 row observation level summary

These broom functions currently only work with parsnip objects not raw workflows objects. To use these functions with workflows we need to first use the pull_workflow_fit() function.

# A tibble: 584 x 5
   term        estimate std.error statistic p.value
   <chr>          <dbl>     <dbl>     <dbl>   <dbl>
 1 (Intercept)    9.60        NaN       NaN     NaN
 2 id1027.0001    1.20        NaN       NaN     NaN
 3 id1033.1002    1.61        NaN       NaN     NaN
 4 id1055.001     2.78        NaN       NaN     NaN
 5 id1069.0003    0.911       NaN       NaN     NaN
 6 id1073.0023    5.99        NaN       NaN     NaN
 7 id1073.1005    2.80        NaN       NaN     NaN
 8 id1073.1009    1.51        NaN       NaN     NaN
 9 id1073.2003    4.95        NaN       NaN     NaN
10 id1073.5002    2.35        NaN       NaN     NaN
# … with 574 more rows
# A tibble: 1 x 11
  r.squared adj.r.squared sigma statistic p.value    df logLik   AIC   BIC
      <dbl>         <dbl> <dbl>     <dbl>   <dbl> <int>  <dbl> <dbl> <dbl>
1         1           NaN   NaN       NaN     NaN   584    Inf  -Inf  -Inf
# … with 2 more variables: deviance <dbl>, df.residual <int>
# A tibble: 584 x 41
   value id    fips    lat   lon  CMAQ zcta_area zcta_pop imp_a500
   <dbl> <fct> <fct> <dbl> <dbl> <dbl>     <dbl>    <dbl>    <dbl>
 1  9.60 1003… 1003   30.5 -87.9  8.10 190980522    27829   0.0173
 2 10.8  1027… 1027   33.3 -85.8  9.77 374132430     5103   1.97  
 3 11.2  1033… 1033   34.8 -87.7  9.40  16716984     9042  19.2   
 4 12.4  1055… 1055   34.0 -86.0  9.24 154069359    20045  16.5   
 5 10.5  1069… 1069   31.2 -85.4  9.12 162685124    30217  19.1   
 6 15.6  1073… 1073   33.6 -86.8 10.2   26929603     9010  41.8   
 7 12.4  1073… 1073   33.3 -87.0 10.2  166239542    16140   1.70  
 8 11.1  1073… 1073   33.5 -87.3  8.16 385566685     3699   0     
 9 14.6  1073… 1073   33.5 -86.9 10.2   10636977    11458  43.6   
10 12.0  1073… 1073   33.7 -86.7  9.30 150661846    21725   1.48  
# … with 574 more rows, and 32 more variables: imp_a15000 <dbl>,
#   county_area <dbl>, county_pop <dbl>, log_dist_to_prisec <dbl>,
#   log_pri_length_5000 <dbl>, log_pri_length_25000 <dbl>,
#   log_prisec_length_500 <dbl>, log_prisec_length_1000 <dbl>,
#   log_prisec_length_5000 <dbl>, log_prisec_length_10000 <dbl>,
#   log_nei_2008_pm10_sum_15000 <dbl>, log_nei_2008_pm10_sum_25000 <dbl>,
#   popdens_county <dbl>, popdens_zcta <dbl>, nohs <dbl>, somehs <dbl>,
#   hs <dbl>, somecollege <dbl>, associate <dbl>, bachelor <dbl>,
#   grad <dbl>, pov <dbl>, hs_orless <dbl>, urc2013 <dbl>, aod <dbl>,
#   state_California <dbl>, city_Not.in.a.city <dbl>, .fitted <dbl>,
#   .se.fit <dbl>, .resid <dbl>, .hat <dbl>, .sigma <dbl>
# A tibble: 33 x 5
   term         estimate std.error statistic  p.value
   <chr>           <dbl>     <dbl>     <dbl>    <dbl>
 1 (Intercept)  2.22e+ 2  1.20e+ 2     1.85  6.51e- 2
 2 lat          3.77e- 2  2.45e- 2     1.54  1.24e- 1
 3 lon          3.02e- 2  9.31e- 3     3.25  1.23e- 3
 4 CMAQ         2.90e- 1  4.29e- 2     6.75  3.66e-11
 5 zcta_area    3.59e-10  3.04e-10     1.18  2.38e- 1
 6 zcta_pop     7.99e- 6  5.55e- 6     1.44  1.50e- 1
 7 imp_a500     6.54e- 3  7.49e- 3     0.874 3.82e- 1
 8 imp_a15000  -1.25e- 3  1.19e- 2    -0.105 9.16e- 1
 9 county_area -2.24e-11  1.63e-11    -1.38  1.69e- 1
10 county_pop  -2.05e- 7  9.31e- 8    -2.20  2.79e- 2
# … with 23 more rows

OK, so we have fit our model on our training data, which means we have created a model to predict values of air pollution based on the predictors that we have included. Yay!

At this point we could take a look at the accuracy of our model performance, but we will only have one reference point: our testing dataset. And we haven’t done any tuning of our model or cross validation… so generally speaking you should not do this.

However if you were short on time you could continue like this.

need tune_*(), fit_resamples() or last_fit() to get any assessment of fit.

We could stop here and use the yardstick package to evaluate performance. First we would want to fit the model with hmmm not sure if I will do this or just skip and use tune even if we dont have any tuning??

Using parsnip we need to use the baked data testing data… or not???

# A tibble: 292 x 3
   .pred value fips 
   <dbl> <dbl> <fct>
 1 NA    11.7  1049 
 2 NA    13.1  1073 
 3 NA    12.2  1073 
 4 NA    12.2  1089 
 5 NA    11.4  1103 
 6 NA    12.2  1121 
 7  9.52 10.9  4013 
 8 NA    10.6  4021 
 9 NA    14.1  4023 
10 NA     5.83 4025 
# … with 282 more rows

Say we were done optimizing our parameters we could then use the last_fit() function of the workflows package.

We could check out test performance using the collect_metrics() function of the tune package.

model performance :https://medium.com/@limavallantin/metrics-to-measure-machine-learning-model-performance-e8c963665476

Here you can see the predictions for the test set (the 292 rows with predicitions out of the 876 original monitor values) also using the tune package with the collect_predictions() function.

However we would really want to tune parameters and use cross validation for this.

yardstick can’t talk directly to workflows… need tune for that…

Cross validation sample splitting

We will use the rsample package again in order to further implement what are called cross validation techniques. This is also called resampling or repartioning. Note: we are not actually getting new samples from the underlying distribution so the term resampling is a bit of a misnomer.

Cross validation splits our training data into multiple training data sets to allow for an assessment of the accuracy of the model.

Here is a visualization of the concept for cross validation/resampling/repartitioning from Max Kuhn:

Technically creating our testing and training set out of our original training data is sometimes considered a form of cross validation called the holdout method. As we just learned this can give us a better sense of the accuracy of our data in a more generalizable way.

However, we can do a better job of optimizing our model for accuracy if we also perform another type of cross validation on the newly defined training set that we just created. There are many cross validation methods and most can be easily implemented using rsamples package. We will use a very popular method called either k-fold or v-fold cross validation.

This method involves essentially preforming the hold out method iteratively with the training data.

First the training set is divided into k or v equally sized smaller pieces.

Then the model is trained on the model on k-1 or v-1 subsets of the data iteratively (removing a different v or k untill all possible k-1 or v-1 sets have been evaluated) to get a sense of the performance of the model. This is really useful for fine tuning specific aspects of the model in a process called model tuning.

Here is a visualization of how the folds are created:

Note: People typically ignore spatial dependence with cross validation of air pollution monitoring data in the air pollution field, so we will do the same. However, it might make sense to leave out blocks of monitors rather than random individual monitors to help account for some spatial dependence.

The vfold_cv() function of the rsample package can be used to parse the training data into folds for k-fold/v-fold cross validation.

The v argument specifies the number of folds to create. The repeats argument specifies if any samples should be repeated across folds - defualt is FALSE The strata argument specifies a variable to stratify samples across folds (just like in initial_split()).

Again because these are created at random, we need to use the base set.seed() function in order to obtain the same results each time we knit this document.

#  10-fold cross-validation 
# A tibble: 10 x 2
   splits           id    
   <named list>     <chr> 
 1 <split [525/59]> Fold01
 2 <split [525/59]> Fold02
 3 <split [525/59]> Fold03
 4 <split [525/59]> Fold04
 5 <split [526/58]> Fold05
 6 <split [526/58]> Fold06
 7 <split [526/58]> Fold07
 8 <split [526/58]> Fold08
 9 <split [526/58]> Fold09
10 <split [526/58]> Fold10
<525/59/584>
<525/59/584>

Once the folds are created they can be used to evaluate peformance by fitting the model to each of the resamples that we created:

We can fit the model to our cross validation folds using the fit_resamples() function of the tune package, by specifying our workflow object and the cross validation fold object we just created. See here for more information.

We can now take a look at various metrics of performance based on the fit of our 10 cross validation “resamples”. To do this we will use the show_best() function of the tune package.

# A tibble: 1 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard    2.08    10   0.147

Tuning

Now let’s try some tuning.

Let’s take a closer look at how the monitor values vary with latitude and longitude.

We can see that there does not appear to be a single linear relationship for either of these predictors. Thus we might want to think about using splines or this(https://towardsdatascience.com/numerical-interpolation-natural-cubic-spline-52c1157b98ac) or just this(https://tidymodels.github.io/tune/articles/getting_started.html) or this(https://www.psych.mcgill.ca/misc/fda/ex-basis-b1.html) to model the relationship in our training data more closely. For example for the latitude plot (left) if we had 2 lines and one breakpoint called a knot around 40, with the first line having a positive slope and the second with a negative slope this would fit the data more similarly to the blue line shown in the figure.

We can tune for the number of knots by using a step function in the recipes package called step_ns() where ns stands for natural splines. In order to tune for the number of knots or degrees of freedom, we can set the deg_free argument to tune(). This is helpful, becuase we aren’t exactly sure how closely we should be following the relationship with the value and our longitude and latitude data in our training data to achieve good accuracy yet keep our model generalizable for other data.

This is when our cross validation methods become really handy. We can test out different values for the deg_free argument and see how our model performance varies across our training folds to try to find the optimal value.

We will update our recipe to add these steps. It is a good idea to do this for individual predictors because you can name each with the tune argument so that you can keep track of it later. We can see what we intend to tune with the parameters() function of the dials package.

See here for more information about implementing this in tidymodels.

Collection of 2 parameters for tuning

     id parameter type object class
 lon df       deg_free    nparam[+]
 lat df       deg_free    nparam[+]

Genearlly you could use the grid_*() functions of the dials package to create the different combinations of degrees of freedom to test for both variables to optimize the model. In our case we can visably see that if we add more than say 4 or 5 degrees of freedom we will likely overfit the data. So instead of using these functions we will create our own grid using the base seq() and expand.grid() functions.

  lon df lat df
1      1      1
2      3      1
3      5      1
4      1      3
5      3      3
6      5      3
7      1      5
8      3      5
9      5      5

Now we will tune this hyper-parameter (degrees of freedom) for both the lat and lon variables using our cross validation folds. To do this we will use the tune_grid() function of the tune package.

#  10-fold cross-validation 
# A tibble: 10 x 4
   splits           id     .metrics          .notes           
 * <list>           <chr>  <list>            <list>           
 1 <split [525/59]> Fold01 <tibble [18 × 5]> <tibble [18 × 1]>
 2 <split [525/59]> Fold02 <tibble [18 × 5]> <tibble [18 × 1]>
 3 <split [525/59]> Fold03 <tibble [18 × 5]> <tibble [18 × 1]>
 4 <split [525/59]> Fold04 <tibble [18 × 5]> <tibble [18 × 1]>
 5 <split [526/58]> Fold05 <tibble [18 × 5]> <tibble [18 × 1]>
 6 <split [526/58]> Fold06 <tibble [18 × 5]> <tibble [18 × 1]>
 7 <split [526/58]> Fold07 <tibble [18 × 5]> <tibble [18 × 1]>
 8 <split [526/58]> Fold08 <tibble [18 × 5]> <tibble [18 × 1]>
 9 <split [526/58]> Fold09 <tibble [18 × 5]> <tibble [18 × 1]>
10 <split [526/58]> Fold10 <tibble [18 × 5]> <tibble [18 × 1]>
# A tibble: 18 x 7
   `lon df` `lat df` .metric .estimator  mean     n std_err
      <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
 1        1        1 rmse    standard   2.08     10  0.147 
 2        1        1 rsq     standard   0.433    10  0.0504
 3        1        3 rmse    standard   1.99     10  0.149 
 4        1        3 rsq     standard   0.483    10  0.0483
 5        1        5 rmse    standard   2.00     10  0.151 
 6        1        5 rsq     standard   0.477    10  0.0475
 7        3        1 rmse    standard   2.00     10  0.160 
 8        3        1 rsq     standard   0.475    10  0.0557
 9        3        3 rmse    standard   1.91     10  0.159 
10        3        3 rsq     standard   0.519    10  0.0508
11        3        5 rmse    standard   1.90     10  0.159 
12        3        5 rsq     standard   0.526    10  0.0514
13        5        1 rmse    standard   2.00     10  0.162 
14        5        1 rsq     standard   0.469    10  0.0576
15        5        3 rmse    standard   1.92     10  0.166 
16        5        3 rsq     standard   0.512    10  0.0565
17        5        5 rmse    standard   1.90     10  0.171 
18        5        5 rsq     standard   0.519    10  0.0613
# A tibble: 18 x 7
   `lon df` `lat df` .metric .estimator  mean     n std_err
      <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
 1        1        1 rmse    standard   2.08     10  0.147 
 2        1        1 rsq     standard   0.433    10  0.0504
 3        1        3 rmse    standard   1.99     10  0.149 
 4        1        3 rsq     standard   0.483    10  0.0483
 5        1        5 rmse    standard   2.00     10  0.151 
 6        1        5 rsq     standard   0.477    10  0.0475
 7        3        1 rmse    standard   2.00     10  0.160 
 8        3        1 rsq     standard   0.475    10  0.0557
 9        3        3 rmse    standard   1.91     10  0.159 
10        3        3 rsq     standard   0.519    10  0.0508
11        3        5 rmse    standard   1.90     10  0.159 
12        3        5 rsq     standard   0.526    10  0.0514
13        5        1 rmse    standard   2.00     10  0.162 
14        5        1 rsq     standard   0.469    10  0.0576
15        5        3 rmse    standard   1.92     10  0.166 
16        5        3 rsq     standard   0.512    10  0.0565
17        5        5 rmse    standard   1.90     10  0.171 
18        5        5 rsq     standard   0.519    10  0.0613
# A tibble: 1 x 7
  `lon df` `lat df` .metric .estimator  mean     n std_err
     <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
1        5        5 rmse    standard    1.90    10   0.171

Linear Regression Model with PCA

We wtill want to use the lm package for our regression so we can use the same model object:

Linear Regression Model Specification (regression)

Computational engine: lm 

We can create another workflow:

══ Workflow ═════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ─────────────────────────────────────────────────────────────────────────────
2 Recipe Steps

● step_dummy()
● step_pca()

── Model ────────────────────────────────────────────────────────────────────────────────────
Linear Regression Model Specification (regression)

Computational engine: lm 

Fit the cross validation samples:

Look at the performance:

# A tibble: 2 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard   2.69     10  0.244 
2 rsq     standard   0.214    10  0.0511

And we can compare this with our previous performance:

# A tibble: 2 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard   2.08     10  0.147 
2 rsq     standard   0.433    10  0.0504

Let’s review everything:

check_new_values: This check will break the bake function if any of the checked columns does contain values it did not contain when prep was called on the recipe. If the check passes, nothing is changed to the data

check_range creates a specification of a recipe check that will check if the range of a numeric variable changed in the new data.

parameter vs hyperparameter

prepper for cross validation?

great blog about cross validation etc https://towardsdatascience.com/train-test-split-and-cross-validation-in-python-80b61beca4b6

Data Visualization

Summary

We have evaluated average consumption estimates of 15 dietary factors with probably non-communicable disease (NCD) risk from 195 different countries around the world. To do so we imported data from a PDF using the pdftools package, as well as data from two CSV files using readr. We used tidyverse packages such as dplyr, stringr, and tidy to clean and join the data from the PDF with the CSV files.

We learned that Regression is a powerful and flexible statistical tool that simplifies or estimates the relationships between variables using a mathematical model. We learned about the utility of the regression to compare groups, look for associations between variables, and to predict outcomes based on multiple predictor or explanatory variables. We then compared this to other popular tests like the \(t\)-test and the ANOVA. We learned that these tests are actually equivalent to specialized types of regressions.

Our statistical analysis focused on evaluating differences in the consumption of red meat around the world between females and males and across different age groups. First we looked at the assumptions of \(t\)-tests and regressions, and determined that the relative percentage data of red meat consumption to the optimal guideline suggested amount was right skewed. We learned that we could transform the data by taking the log of these values to achieve more normally distributed data. To compare males and females we used a \(t\)-test and learned that a \(t\)-test is a specialized form of a linear regression. To compare the 15 different age groups we used an ANOVA and learned that the ANOVA is also a specialized form of linear regression. We examined how we obtained the same results using either statistical test. This was also the case if we looked at the effect of gender and controlled for the paired country structure in the data by either including location_name in the model as another term or by using a mixed effects model to control for this structure as a random effect but not specifically test for the influence of location_name on red meat consumption estimates. We learned that fixed effects are those that we wish to evaluate, while random effects are those that may influence the relationships of our variables of interest but that we do not wish to actively evaluate. Using these tests and models, we determined that males consume more red meat than women on average around the world.

Our ANOVA analysis of age determined that indeed there at least one age group consumed a significantly different amount of red meat compared to the other age groups, and this was still the case when we controlled location_name. However, we learned that we could that the ANOVA does not provide information about which age groups are different. We learned how the regression however could provide some comparisons of different age groups relative to the reference age group. Furthermore, our data visualizations allowed us to determine that in general red met consumption appears to be higher in the younger age groups relative to the older age groups.

Finally, we also looked at differences in red meat consumption between the different countries and saw in our ANOVA analysis and our regression analysis that there were significant differences. We were able to use a regression that included sex, age_group_name, and location_name to evaluate the influence of each of the three demographic factors on consumption while controlling or accounting for the other two. Our results demonstrated that all three influenced or were associated with red meat consumption.

In preforming our statistical analyses we learned about the assumptions of the \(t\)-test, the regression, and the ANOVA. We also learned about important methods to tests these assumptions.

\(t\)-test assumptions:

  1. Normality of the data for both groups (this is not as much of an issue if the number of observations is relatively large total n>30 - can evaluate by plotting the distribution and by creating Q-Q plots)
  2. Equal variance between the two groups (make sure you do the correct test if the data is not normal)
  3. Balanced sample sizes of the two groups
  4. Independent observations (or independent paired observations)

We can evaluate if our data is normally distributed by plotting the distribution and by creating [Q-Q plots](Q-Q Plots to compare the distribution of our data to the theoretical normal distribution.

If our data is not normally distributed, we can consider these options:

  1. We can still perform a \(t\)-test if our n is large
  2. We can transform the data before performing a \(t\)-test
  3. We can use a nonparametric test (Wilcoxon signed rank test, the Wilcoxon rank sum test, and the Two-sample Kolmogorov-Smirnov (KS) test)
  4. We can perform a \(t\)-test with resampling methods (which should be especially considered when the groups are imbalanced)

See this case study for more information on \(t\)-test assumptions.

We learned that we can test if 2 groups have equal variance using:
1) the F test with var.test()
2) Mood’s test using mood.test() (use if the data is not normally distributed)

Linear regression assumptions:

L (linear) - There is a linear relationship between the variables.
I (independent) - The samples are independent from one another.
N (normal) - The residuals are normally distributed.
E (equal variances) - The variance of the residuals of the groups is similar.
It is also important that predictor variables are not correlated with one another.

ANOVA assumptions:

  1. Normality of the data for all tested groups (less of an issue if the number of observations is relatively large total n>30)
  2. Equal variance between the groups - aka Homogeneity of variance (make sure you do the correct test if the data is not normal)
  3. Balanced sample sizes of the groups
  4. Independent observations (or independent paired observations)

We learned about three tests for examining the equality of variance of 3 or more groups: 1) Bartlett’s test (works well if the data appears to be normally distributed) 2) Fligner-Killeen test is nonparametric and does not assume normality 3) Levene’s test, is more robust to violations of normality than the Bartlett’s test, but not as robust as the Fligner- Killeen test

Using the ggplot2 package we were able to visualize trends in the data and to compare consumption of these dietary factors in the US with that of the other countries. We see that the populations in many countries are over-consuming foods that are associated with health risk when over-consumed. In particular processed meat and sugar-sweetened beverages appear to be the most over consumed. Importantly both of these appear to be consumed at higher quantities by males and younger adults. People in the US appear to consume less sugar-sweetened beverages than other countries, however, people are still over-consuming. Processed meat however appears to be especially bad in the US. In terms of food that need to be consumed in adequate amounts to overcome health risk, nearly all countries for all factors are not reaching guideline levels. However, there are some countries consuming more than adequate amounts of legumes, vegetables, fruits and fiber. People in the US appear to eat more milk products and consume more omega-3 fatty acid and calcium rich foods than other countries. All countries including the US consume very low levels of polyunsaturated fatty acids. These polyunsaturated fatty acids are abundant in seeds, nuts, avocados, as well as fish. Likely the low level of consumption of nuts and seeds contributes to these low polyunsaturated fatty acid estimates. The supplementary table included in the article suggests that poor consumption of polyunsaturated fatty acids is associated with ischemic heart disease. The article takes this data further to evaluate the association of consumption levels of these foods with mortality.

Analyses like the one in our case study are important for defining which groups could benefit the most from interventions, education, and policy changes when attempting to mitigate public health challenges. You can see in the article however that many additional considerations would be involved to perform a more thorough analysis to adequately understand the data enough to recommend policy changes.

Suggested Homework

Students can evaluate consumption estimates of another dietary factor besides red meat.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBQcmVkaWN0aW5nIEFubnVhbCBBaXIgUG9sbHV0aW9uICIKY3NzOiBzdHlsZS5jc3MKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKCi0tLQo8c3R5bGU+CiNUT0MgewogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL2ltZy9sb2dvLmpwZyIpOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsKICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Owp9Cjwvc3R5bGU+CgoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQpgYGAKCiMjIyMKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YSBzZXQsIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgbWFraW5nIHBvbGljeSBkZWNpc2lvbnMgd2l0aG91dCBleHRlcm5hbCBjb25zdWx0YXRpb24gZnJvbSBzY2llbnRpZmljIGV4cGVydHMuIAoKIyMgTW90aXZhdGlvbgpBIHZhcmlldHkgb2YgZGlmZmVyZW50IHNvdXJjZXMgY29udHJpYnV0ZSBkaWZmZXJlbnQgdHlwZXMgb2YgcG9sbHV0YW50cyB0byB3aGF0IHdlIGNhbGwgYWlyIHBvbGx1dGlvbi4gClNvbWUgc291cmNlcyBhcmUgbmF0dXJhbCB3aGlsZSBvdGhlcnMgYXJlIGFudGhyb3BvZ2VuaWMgKGh1bWFuIGRlcml2ZWQpOgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNjAwIiBzcmM9Imh0dHBzOi8vd3d3Lm5wcy5nb3Yvc3ViamVjdHMvYWlyL2ltYWdlcy9Tb3VyY2VzX0dyYXBoaWNfSHVnZS5qcGc/bWF4d2lkdGg9MTIwMCZtYXhoZWlnaHQ9MTIwMCZhdXRvcm90YXRlPWZhbHNlIj4KPC9wPgoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vdXJsP3NhPWkmdXJsPWh0dHBzJTNBJTJGJTJGd3d3Lm5wcy5nb3YlMkZzdWJqZWN0cyUyRmFpciUyRnNvdXJjZXMuaHRtJnBzaWc9QU92VmF3MnY3QVZ4U0Y4WlNBUEVoTnVkVnRiTiZ1c3Q9MTU4NTc3MDk2NjIxNzAwMCZzb3VyY2U9aW1hZ2VzJmNkPXZmZSZ2ZWQ9MENBSVFqUnhxRndvVENQRE42NnFfeGVnQ0ZRQUFBQUFkQUFBQUFCQUQpXQoKIyMjIyBNYWpvciB0eXBlcyBvZiBhaXIgcG9sbHV0YW50cwoKMSkgKipHYXNlb3VzKiogLSBDYXJib24gTW9ub3hpZGUgKENPKSwgT3pvbmUgKE9+M34pLCBOaXRyb2dlbiBPeGlkZXMoTk8sIE5PfjJ+KSwgU3VscGhlciBEaW94aWRlIChTT34yfikKMikgKipQYXJ0aWN1bGF0ZSoqIC0gc21hbGwgbGlxdWlkcyBhbmQgc29saWRzIHN1c3BlbmRlZCBpbiB0aGUgYWlyIChpbmNsdWRlcyBsZWFkLSBjYW4gaW5jbHVkZSBjZXJ0YWluIHR5cGVzIG9mIGR1c3QpCjMpICoqRHVzdCoqIC0gc21hbGwgc29saWRzIChsYXJnZXIgdGhhbiBwYXJ0aWN1bGF0ZXMpIHRoYXQgY2FuIGJlIHN1c3BlbmRlZCBpbiB0aGUgYWlyIGZvciBzb21lIHRpbWUgYnV0IGV2ZW50dWFsbHkgc2V0dGxlCjQpICoqQmlvbG9naWNhbCoqIC0gcG9sbGVuLCBiYWN0ZXJpYSwgdmlydXNlcywgbW9sZCBzcG9yZXMKClNlZSBbaGVyZV0paHR0cDovL3d3dy5yZWRsb2dlbnYuY29tL3dvcmtlci1zYWZldHkvcGFydC0xLWR1c3QtYW5kLXBhcnRpY3VsYXRlLW1hdHRlcikgZm9yIG1vcmUgZGV0YWlsIG9uIHRoZSB0eXBlcyBvZiBwb2xsdXRhbnRzIGluIHRoZSBhaXIuCgoKIyMjIyBQYXJ0aWN1bGF0ZSBwb2xsdXRpb24gCgpBaXIgcG9sbHV0aW9uIHBhcnRpY3VsYXRlcyBhcmUgZ2VuZXJhbGx5IGRlc2NyaWJlZCBieSB0aGVpciAqKnNpemUqKi4KClRoZXJlIGFyZSAzIG1ham9yIGNhdGVnb3JpZXM6CgoxKSAqKkxhcmdlIENvYXJzZSoqIFBhcnRpY3VsYXRlIE1hdGVyIC0gaGFzIGRpYW1ldGVyIG9mID4xMCBtaWNyb21ldGVycyAoMTAgwrVtKSAKCjIpICoqQ29hcnNlKiogUGFydGljdWxhdGUgTWF0ZXIgKGNhbGxlZCAqKlBNfjEwLTIuNX4qKikgLSBoYXMgZGlhbWV0ZXIgb2YgYmV0d2VlbiAyLjUgwrVtIGFuZCAxMCDCtW0KCjMpICoqRmluZSoqIFBhcnRpY3VsYXRlIE1hdGVyIChjYWxsZWQgKipQTX4yLjV+KiopIC0gaGFzIGRpYW1ldGVyIG9mIDwgMi41IMK1bSAKCioqUE1+MTB+KiogaW5jbHVkZXMgYW55IHBhcnRpY3VsYXRlIG1hdGVyIDwxMCDCtW0gKGJvdGggY29hcnNlIGFuZCBmaW5lIHBhcnRpY3VsYXRlIG1hdGVyKQoKSGVyZSB5b3UgY2FuIHNlZSBob3cgdGhlc2Ugc2l6ZXMgY29tcGFyZSB3aXRoIGEgaHVtYW4gaGFpcjoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjYwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwbTIuNV9zY2FsZV9ncmFwaGljLWNvbG9yXzIuanBnIikpCmBgYAoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3LmVwYS5nb3YvcG0tcG9sbHV0aW9uL3BhcnRpY3VsYXRlLW1hdHRlci1wbS1iYXNpY3MpXQoKPCEtLSA8cCBhbGlnbj0iY2VudGVyIj4gLS0+CjwhLS0gICA8aW1nIHdpZHRoPSI1MDAiIHNyYz0iaHR0cHM6Ly93d3cuc2Vuc2lyaW9uLmNvbS9pbWFnZXMvc2Vuc2lyaW9uLXNwZWNpYWxpc3QtYXJ0aWNsZS1maWd1cmUtMS1jZGQ3MC5qcGciPiAtLT4KPCEtLSA8L3A+IC0tPgoKCjx1PlRoZSBmb2xsb3dpbmcgcGxvdCBhbmQgdGFibGUgc2hvdyB0aGUgcmVsYXRpdmUgc2l6ZXMgb2YgdGhlc2UgZGlmZmVyZW50IHBvbGx1dGFudHMgaW4gbWljcm9tZXRlcnMowrVtKTo8L3U+Cgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI2MDAiIHNyYz0iaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi9kL2RmL0FpcmJvcm5lLXBhcnRpY3VsYXRlLXNpemUtY2hhcnQuc3ZnLzgwMHB4LUFpcmJvcm5lLXBhcnRpY3VsYXRlLXNpemUtY2hhcnQuc3ZnLnBuZyI+CjwvcD4KCiMjIyMjIFtbc291cmNlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QYXJ0aWN1bGF0ZXMpXQoKCjxwIGFsaWduPSJjZW50ZXIiPgogIDxpbWcgd2lkdGg9IjUwMCIgc3JjPSJodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvZmlsZXMvQXJ0aWNsZXMvNTA1NTcwL2ZwdWJoLTA4LTAwMDE0LUhUTUwvaW1hZ2VfbS9mcHViaC0wOC0wMDAxNC10MDAyLmpwZyI+CjwvcD4KCiMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcHViaC4yMDIwLjAwMDE0L2Z1bGwpXQoKCjx1PlRoaXMgdGFibGUgc2hvd3MgaG93IGRlZXBseSBzb21lIG9mIHRoZSBzbWFsbGVyIGZpbmUgcGFydGljbGVzIGNhbiBwZW5ldHJhdGUgd2l0aGluIHRoZSBodW1hbiBib2R5OjwvdT4KCjxwIGFsaWduPSJjZW50ZXIiPgogIDxpbWcgd2lkdGg9IjUwMCIgc3JjPSJodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvZmlsZXMvQXJ0aWNsZXMvNTA1NTcwL2ZwdWJoLTA4LTAwMDE0LUhUTUwvaW1hZ2VfbS9mcHViaC0wOC0wMDAxNC10MDAxLmpwZyI+CjwvcD4KCiMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcHViaC4yMDIwLjAwMDE0L2Z1bGwpXQoKCiMjIyMgTmVnYXRpdmUgSW1wYWN0IG9mIFBhcnRpY3VsYXRlIEV4cG9zdXJlIG9uIEhlYWx0aCAKCkV4cG9zdXJlIHRvIGFpciBwb2xsdXRpb24gaXMgYXNzb2NpYXRlZCB3aXRoIGhpZ2hlciByYXRlcyBvZiBbbW9ydGFsaXR5XShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM1NzgzMTg2Lyl7dGFyZ2V0PSJfYmxhbmsifSBpbiBvbGRlciBhZHVsdHMgYW5kIGlzIGtub3duIHRvIGJlIGEgcmlzayBmYWN0b3IgZm9yIG1hbnkgZGlzZWFzZXMgYW5kIGNvbmRpdGlvbnMgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzoKCjEpIFtBc3RobWFdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcHVibWVkLzI5MjQzOTM3KXt0YXJnZXQ9Il9ibGFuayJ9IC0gZmluZSBwYXJ0aWNsZSBleHBvc3VyZSAoKipQTX4yLjV+KiopIHdhcyBmb3VuZCB0byBiZSBhc3NvY2lhdGVkIHdpdGggaGlnaGVyIHJhdGVzIG9mIGFzdGhtYSBpbiBjaGlsZHJlbgoyKSBbSW5mbGFtbWF0aW9uIGluIHR5cGUgMSBkaWFiZXRlc10oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMzE0MTk3NjUpe3RhcmdldD0iX2JsYW5rIn0gLSBmaW5lIHBhcnRpY2xlIGV4cG9zdXJlICgqKlBNfjIuNX4qKikgZnJvbSB0cmFmZmljLXJlbGF0ZWQgYWlyIHBvbGx1dGlvbiB3YXMgYXNzb2NpYXRlZCB3aXRoIGluY3JlYXNlZCBtZWFzdXJlcyBvZiBpbmZsYW1tYXRvcnkgbWFya2VycyBpbiB5b3V0aHMgd2l0aCB0eXBlIDEgZGlhYmV0ZXMKMykgW0x1bmcgZnVuY3Rpb24gYW5kIGVtcGh5c2VtYV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMzE0MDgxMzUpe3RhcmdldD0iX2JsYW5rIn0gLSBoaWdoZXIgY29uY2VudHJhdGlvbnMgb2Ygb3pvbmUgKE9+M34pLCBuaXRyb2dlbiBveGlkZXMgKE5Pfnh+KSwgYmxhY2sgY2FyYm9uLCBhbmQgZmluZSBwYXJ0aWNsZSBleHBvc3VyZSAqKlBNfjIuNX4qKiAsIGF0IHN0dWR5IGJhc2VsaW5lIHdlcmUgc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggZ3JlYXRlciBpbmNyZWFzZXMgaW4gcGVyY2VudCBlbXBoeXNlbWEgcGVyIDEwIHllYXJzIAo0KSBbTG93IGJpcnRod2VpZ2h0XShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8zMTM4NjY0Myl7dGFyZ2V0PSJfYmxhbmsifSAtIGZpbmUgcGFydGljbGUgZXhwb3N1cmUoKipQTX4yLjV+KiopIHdhcyBhc3NvY2lhdGVkIHdpdGggbG93ZXIgYmlydGggd2VpZ2h0IGluIGZ1bGwtdGVybSBsaXZlIGJpcnRocwo1KSBbVmlyYWwgSW5mZWN0aW9uXShodHRwczovL3d3dy50YW5kZm9ubGluZS5jb20vZG9pL2Z1bGwvMTAuMTA4MC8wODk1ODM3MDcwMTY2NTQzNCl7dGFyZ2V0PSJfYmxhbmsifSAtIGhpZ2hlciByYXRlcyBvZiBpbmZlY3Rpb24gYW5kIGluY3JlYXNlZCBzZXZlcml0eSBvZiBpbmZlY3Rpb24gYXJlIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgZXhwb3N1cmVzIHRvIHBvbGx1dGlvbiBsZXZlbHMgaW5jbHVkaW5nIGZpbmUgcGFydGljbGUgZXhwb3N1cmUgKCoqUE1+Mi41fioqKQoKU2VlIHRoaXMgW3JldmlldyBhcnRpY2xlXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcHViaC4yMDIwLjAwMDE0L2Z1bGwpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgc291cmNlcyBvZiBhaXIgcG9sbHV0aW9uIGFuZCB0aGUgaW5mbHVlbmNlIG9mIGFpciBwb2xsdXRpb24gb24gaGVhbHRoLgoKIyMjIyBTcGFyc2UgTW9uaXRvcmluZyBpcyBQcm9ibGVtYXRpYyBmb3IgUHVibGljIEhlYWx0aAoKSGlzdG9yaWNhbGx5IGVwaWRlbWlvbG9naWNhbCBzdHVkaWVzIHdvdWxkIGFzc2VzcyB0aGUgaW5mbHVlbmNlIG9mIGFpciBwb2xsdXRpb24gb24gaGVhbHRoIG91dGNvbWVzIGJ5IHJlbHlpbmcgb24gYSBudW1iZXIgb2YgbW9uaXRvcnMgbG9jYXRlZCBhcm91bmQgdGhlIGNvdW50cnkuIEhvd2V2ZXIgYXMgY2FuIGJlIHNlZW4gaW4gdGhlIGZvbGxvd2luZyBmaWd1cmUsIHRoZXNlIG1vbml0b3JzIHJlbWFpbiB0byBiZSByZWxhdGl2ZWx5IHNwYXJzZSBpbiBjZXJ0YWluIHJlZ2lvbnMgb2YgdGhlIGNvdW50cnkuIEZ1cnRoZXJtb3JlLCBkcmFtYXRpYyBkaWZmZXJlbmNlcyBpbiBwb2xsdXRpb24gcmF0ZXMgY2FuIGJlIHNlZW4gZXZlbiB3aXRoaW4gdGhlIHNhbWUgY2l0eS4KCjxwIGFsaWduPSJjZW50ZXIiPgogIDxpbWcgd2lkdGg9IjQwMCIgc3JjPSJodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0MTM3MjcyL2Jpbi8xNDc2LTA2OVgtMTMtNjMtMS5qcGciPgo8L3A+CgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly9laGpvdXJuYWwuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni8xNDc2LTA2OVgtMTMtNjMpXQoKVGhpcyBsYWNrIG9mIGdyYW51bGFyaXR5IGluIGFpciBwb2xsdXRpb24gbW9uaXRvcmluZyBoYXMgaGluZGVyZWQgb3VyIGFiaWxpdHkgdG8gZGlzY2VybiB0aGUgZnVsbCBpbXBhY3Qgb2YgYWlyIHBvbGx1dGlvbiBvbiBoZWFsdGggYW5kIHRvIGlkZW50aWZ5IGF0LXJpc2sgbG9jYXRpb25zLiAKCgojIyMjIE1hY2hpbmUgTGVhcm5pbmcgT2ZmZXJzIGEgU29sdXRpb24KCkFuIFthcnRpY2xlXShodHRwczovL2Voam91cm5hbC5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2LzE0NzYtMDY5WC0xMy02Myl7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gdGhlICpFbnZpcm9ubWVudGFsIEhlYWx0aCogam91cm5hbCBkZWFsdCB3aXRoIHRoaXMgaXNzdWUgYnkgdXNpbmcgZGF0YSBhYm91dCBwb3B1bGF0aW9uIGRlbnNpdHksIHJvYWQgZGVuc2l0eSwgYW1vbmcgb3RoZXIgZmVhdHVyZXMgdG8gbW9kZWwgb3IgcHJlZGljdCBhaXIgcG9sbHV0aW9uIGxldmVscyBhdCBhIG1vcmUgbG9jYWxpemVkIHNjYWxlIHVzaW5nIG1hY2hpbmUgbGVhcm5pbmcgbWV0aG9kcy4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAidGhlcGFwZXIucG5nIikpCmBgYAoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KWWFub3NreSwgSi4gRC4gZXQgYWwuIFNwYXRpby10ZW1wb3JhbCBtb2RlbGluZyBvZiBwYXJ0aWN1bGF0ZSBhaXIgcG9sbHV0aW9uIGluIHRoZSBjb250ZXJtaW5vdXMgVW5pdGVkIFN0YXRlcyB1c2luZyBnZW9ncmFwaGljIGFuZCBtZXRlb3JvbG9naWNhbCBwcmVkaWN0b3JzLiAqRW52aXJvbiBIZWFsdGgqIDEzLCA2MyAoMjAxNCkuCgojIyMjCgpUaGUgYXV0aG9ycyBvZiB0aGlzIGFydGljbGUgc3RhdGUgdGhhdDoKCj4gIkV4cG9zdXJlIHRvIGF0bW9zcGhlcmljIHBhcnRpY3VsYXRlIG1hdHRlciAoUE0pIHJlbWFpbnMgYW4gaW1wb3J0YW50IHB1YmxpYyBoZWFsdGggY29uY2VybiwKYWx0aG91Z2ggaXQgcmVtYWlucyBkaWZmaWN1bHQgdG8gcXVhbnRpZnkgYWNjdXJhdGVseSBhY3Jvc3MgbGFyZ2UgZ2VvZ3JhcGhpYyBhcmVhcyB3aXRoIHN1ZmZpY2llbnRseSBoaWdoIHNwYXRpYWwKcmVzb2x1dGlvbi4gUmVjZW50IGVwaWRlbWlvbG9naWMgYW5hbHlzZXMgaGF2ZSBkZW1vbnN0cmF0ZWQgdGhlIGltcG9ydGFuY2Ugb2Ygc3BhdGlhbGx5LSBhbmQgdGVtcG9yYWxseS1yZXNvbHZlZApleHBvc3VyZSBlc3RpbWF0ZXMsIHdoaWNoIHNob3cgbGFyZ2VyIFBNLW1lZGlhdGVkIGhlYWx0aCBlZmZlY3RzIGFzIGNvbXBhcmVkIHRvIG5lYXJlc3QgbW9uaXRvciBvcgpjb3VudHktc3BlY2lmaWMgYW1iaWVudCBjb25jZW50cmF0aW9ucy4iIAoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjcwMCBweCIsIGV2YWwgPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImRlYXRocy5wbmciKSkKYGBgCgpUaGUgYXJ0aWNsZSBhYm92ZSBleHBsYWlucyB0aGF0IG1hY2hpbmUgbGVhcm5pbmcgbWV0aG9kcyBjYW4gYmUgdXNlZCB0byBwcmVkaWN0IGFpciBwb2xsdXRpb24gbGV2ZWxzIHdoZW4gdHJhZGl0aW9uYWwgbW9uaXRvcmluZyBzeXN0ZW1zIGFyZSBub3QgYXZhaWxhYmxlIGluIGEgcGFydGljdWxhciBhcmVhIG9yIHdoZW4gdGhlcmUgaXMgbm90IGVub3VnaCBzcGF0aWFsIGdyYW51bGFyaXR5IHdpdGggY3VycmVudCBtb25pdG9yaW5nIHN5c3RlbXMuIFdlIHdpbGwgdXNlIHNpbWlsYXIgbWV0aG9kcyB0byBwcmVkaWN0IGFubnVhbCBhaXIgcG9sbHV0aW9uIGxldmVscyBzcGF0aWFsbHkgd2l0aGluIHRoZSBVUy4KCgojIyMgTWFpbiBRdWVzdGlvbnMKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb246IDwvdT48L2I+CgoxKSBDYW4gd2UgcHJlZGljdCBhbm51YWwgYXZlcmFnZSBhaXIgcG9sbHV0aW9uIGNvbmNlbnRyYXRpb25zIGF0IHRoZSBncmFudWxhcml0eSBvZiB6aXAgY29kZSByZWdpb25hbCBsZXZlbHMgdXNpbmcgcHJlZGljdG9ycyBzdWNoIGFzIGRhdGEgYWJvdXQgcG9wdWxhdGlvbiBkZW5zaXR5LCB1cmJhbml6YXRpb24sIHJvYWQgZGVuc2l0eSwgYXMgd2VsbCBhcywgc2F0ZWxsaXRlIHBvbGx1dGlvbiBkYXRhIGFuZCBjaGVtaWNhbCBtb2RlbGluZyBkYXRhPwoKIyMjIwoKIyMjIExlYXJuaW5nIE9iamVjdGl2ZXMgCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgd2FsayB5b3UgdGhyb3VnaCBpbXBvcnRpbmcgZGF0YSBmcm9tIENTViBmaWxlcyBhbmQgcGVyZm9ybWluZyBtYWNoaW5lIGxlYXJuaW5nIG1ldGhvZHMgdG8gcHJlZGljdCBvdXIgb3V0Y29tZSB2YXJpYWJsZSBvZiBpbnRlcmVzdCAoaW4gdGhpcyBjYXNlIGFubnVhbCBmaW5lIHBhcnRpY2xlIGFpciBwb2xsdXRpb24gZXN0aW1hdGVzKS4gV2Ugd2lsbCBlc3BlY2lhbGx5IGZvY3VzIG9uIHVzaW5nIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnMgZnJvbSB0aGUgW2BUaWR5dmVyc2VgXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSwgYW5kIG1vcmUgc3BlY2lmaWNhbGx5IHRoZSBbYHRpZHltb2RlbHNgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGlkeW1vZGVscy90aWR5bW9kZWxzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBwYWNrYWdlL2Vjb3N5c3RlbSBwcmltYXJpbHkgZGV2ZWxvcGVkIGFuZCBtYWludGFpbmVkIGJ5IFtNYXggS3Vobl0oaHR0cHM6Ly9yZXNvdXJjZXMucnN0dWRpby5jb20vYXV0aG9ycy9tYXgta3Vobil7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW0RhdmlzIFZhdWdoYW5dKGh0dHBzOi8vcmVzb3VyY2VzLnJzdHVkaW8uY29tL2F1dGhvcnMvZGF2aXMtdmF1Z2hhbil7dGFyZ2V0PSJfYmxhbmsifS4gVGhpcyBwYWNrYWdlIGxvYWRzIG1vcmUgbW9kZWxpbmcgcmVsYXRlZCBwYWNrYWdlcyBsaWtlIGByc2FtcGxlYCwgYHJlY2lwZXNgLCBgcGFyc25pcGAsIGB5YXJkc3RpY2tgLCAgYW5kIGBkaWFsc2AuIFdlIHdpbGwgYWxzbyBicmllZmx5IGNvdmVyIHRoZSBgd29ya2Zsb3dzYCBhbmQgYHR1bmVgIHBhY2thZ2VzLiBUaGUgdGlkeXZlcnNlIGlzIGEgbGlicmFyeSBvZiBwYWNrYWdlcyBjcmVhdGVkIGJ5IFJTdHVkaW8uIFdoaWxlIHNvbWUgc3R1ZGVudHMgbWF5IGJlIGZhbWlsaWFyIHdpdGggcHJldmlvdXMgUiBwcm9ncmFtbWluZyBwYWNrYWdlcywgdGhlc2UgcGFja2FnZXMgbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBlc3BlY2lhbGx5IGVmZmljaWVudC4KCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKYGBge3IsIG91dC53aWR0aCA9ICIxMDBweCIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9wYnMudHdpbWcuY29tL21lZGlhL0RrQkZwU3NXNEFJeXlJTi5wbmciKQpgYGAKCgpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOgoKYGBge3J9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeShza2ltcikKbGlicmFyeShzdW1tYXJ5dG9vbHMpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoR0dhbGx5KQoKbGlicmFyeSh0aWR5bW9kZWxzKSMgYnJvb20sIGRpYWxzLCBpbmZlciwgcGFyc25pcCwgcHVycnIsIHJlY2lwZXMsIHJzYW1wbGUsIHRpYmJsZSwgeWFyZHN0aWNrCgpsaWJyYXJ5KHdvcmtmbG93cykKbGlicmFyeSh0dW5lKQoKIyBsaWJyYXJ5KHN0cmluZ3IpCiMgbGlicmFyeShwdXJycikKIyBsaWJyYXJ5KHRpYmJsZSkKIyBsaWJyYXJ5KHRpZHlyKQojIGxpYnJhcnkoZ2dwbG90MikKIyBsaWJyYXJ5KGdncHVicikKIyBsaWJyYXJ5KGZvcmNhdHMpCiMgbGlicmFyeShsbWVyVGVzdCkKIyBsaWJyYXJ5KGNhcikKIyBsaWJyYXJ5KGdnaXJhcGgpCiMgbGlicmFyeShnZ2ZvcmNlKQojIGxpYnJhcnkodmlyaWRpcykKIyBsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKCiBQYWNrYWdlICAgfCBVc2UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCi0tLS0tLS0tLS0gfC0tLS0tLS0tLS0tLS0KW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSl7dGFyZ2V0PSJfYmxhbmsifSAgICAgICB8IHRvIGVhc2lseSBsb2FkIGFuZCBzYXZlIGRhdGEKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEKW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byB2aWV3L2FycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgCltza2ltcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NraW1yL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGdldCBhbiBvdmVydmlldyBvZiBkYXRhCltzdW1tYXJ5dG9vbHNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9za2ltci9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBnZXQgYW4gb3ZlcnZpZXcgb2YgZGF0YSBpbiBhIGRpZmZlcmVudCBzdHlsZQpbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byB1c2UgdGhlIGAlPD4lYCBwaXBwaW5nIG9wZXJhdG9yIApbR0dhbGx5XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvR0dhbGx5L0dHYWxseS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBjcmVhdGUgY29ycmVsYXRpb24gcGxvdHMgIApbcnNhbXBsZV0oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yc2FtcGxlL2FydGljbGVzL0Jhc2ljcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIHRlc3RpbmcgYW5kIHRyYWluaW5nIHNldHMgYW5kIHRvIHNwbGl0IHRoZSB0cmFpbmluZyBzZXQgZm9yIGNyb3NzLXZhbGlkYXRpb24gIApbcmVjaXBlc10oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yZWNpcGVzLyl7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gcHJlLXByb2Nlc3MgZGF0YSBmb3IgbW9kZWxpbmcgaW4gYSB0aWR5IGFuZCByZXByb2R1Y2libGUgd2F5IGFuZCB0byBleHRyYWN0IHByZS1wcm9jZXNzZWQgZGF0YSAobWFqb3IgZnVuY3Rpb25zIGFyZSBgcmVjaXBlKClgICwgYHByZXAoKWAgYW5kIHZhcmlvdXMgdHJhbnNmb3JtYXRpb24gYHN0ZXBfKigpYCBmdW5jdGlvbnMsIGFzIHdlbGwgYXMgYGp1aWNlKClgIC0gZXh0cmFjdHMgZmluYWwgcHJlcHJvY2Vzc2VkIHRyYWluaW5nIGRhdGEgYW5kIGBiYWtlKClgIC0gYXBwbGllcyByZWNpcGUgc3RlcHMgdG8gdGVzdGluZyBkYXRhKS4gU2VlIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcmVjaXBlcy9yZWNpcGVzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgZm9yIG1vcmUgaW5mby4KW3BhcnNuaXBdKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vcGFyc25pcC8pe3RhcmdldD0iX2JsYW5rIn0gICB8IGFuIGludGVyZmFjZSB0byBjcmVhdGUgbW9kZWxzIChtYWpvciBmdW5jdGlvbnMgYXJlICBgZml0KClgLCBgc2V0X2VuZ2luZSgpYCkKW3lhcmRzdGlja10oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby95YXJkc3RpY2svKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBldmFsdWF0ZSB0aGUgcGVyZm9ybWFuY2Ugb2YgbW9kZWxzCiAKCgpbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvc3RyaW5nci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgdGV4dCB3aXRoaW4gdGhlIFBERiBvZiB0aGUgZGF0YQoKW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBwZXJmb3JtIGZ1bmN0aW9ucyBvbiBhbGwgY29sdW1ucyBvZiBhIHRpYmJsZQpbdGliYmxlXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgfCB0byBjcmVhdGUgZGF0YSBvYmplY3RzIHRoYXQgd2UgY2FuIG1hbmlwdWxhdGUgd2l0aCBkcGx5ci9zdHJpbmdyL3RpZHlyL3B1cnJyClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gc2VwYXJhdGUgZGF0YSB3aXRoaW4gYSBjb2x1bW4gaW50byBtdWx0aXBsZSBjb2x1bW5zCltnZ3Bsb3QyXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYWtlIHZpc3VhbGl6YXRpb25zIHdpdGggbXVsdGlwbGUgbGF5ZXJzCltnZ3B1YnJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3B1YnIvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGVhc2lseSBhZGQgcmVncmVzc2lvbiBsaW5lIGVxdWF0aW9ucyB0byBwbG90cwpbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gY2hhbmdlIGRldGFpbHMgYWJvdXQgZmFjdG9ycyAoY2F0ZWdvcmljYWwgdmFyaWFibGVzKQpbbG1lclRlc3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9sbWVyVGVzdC9sbWVyVGVzdC5wZGYpfCB0byBwZXJmb3JtIGxpbmVhciBtaXhlZCBtb2RlbCB0ZXN0aW5nCltjYXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jYXIvY2FyLnBkZil8IHRvIHBlcmZvcm0gTGV2ZW5lJ3MgVGVzdCBvZiBIb21vZ2VuZWl0eSBvZiBWYXJpYW5jZXMKW2dnaXJhcGhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2lyYXBoL2luZGV4Lmh0bWwpfCB0byBtYWtlIHBsb3RzIGludGVyYWN0aXZlCltnZ2ZvcmNlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dmb3JjZS9nZ2ZvcmNlLnBkZil8IHRvIG1vZGlmeSBmYWNldHMgaW4gcGxvdHMKW3ZpcmlkaXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy92aXJpZGlzL3ZpZ25ldHRlcy9pbnRyby10by12aXJpZGlzLmh0bWwpfCB0byBwbG90IGluIGNvbG9yIHBhbGV0dGUgdGhhdCBpcyBlYXNpbHkgaW50ZXJwcmV0ZWQgYnkgY29sb3JibGluZCBpbmRpdmlkdWFscwpbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQKX19fCgoKClRoZSBmaXJzdCB0aW1lIHdlIHVzZSBhIGZ1bmN0aW9uLCB3ZSB3aWxsIHVzZSB0aGUgYDo6YCB0byBpbmRpY2F0ZSB3aGljaCBwYWNrYWdlIHdlIGFyZSB1c2luZy4gVW5sZXNzIHdlIGhhdmUgb3ZlcmxhcHBpbmcgZnVuY3Rpb24gbmFtZXMsIHRoaXMgaXMgbm90IG5lY2Vzc2FyeSwgYnV0IHdlIHdpbGwgaW5jbHVkZSBpdCBoZXJlIHRvIGJlIGluZm9ybWF0aXZlIGFib3V0IHdoZXJlIHRoZSBmdW5jdGlvbnMgd2Ugd2lsbCB1c2UgY29tZSBmcm9tLgoKCiMjIyBDb250ZXh0CgpUaGUgW1N0YXRlIG9mIEdsb2JhbCBBaXJdKGh0dHBzOi8vd3d3LnN0YXRlb2ZnbG9iYWxhaXIub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSBpcyBhIHJlcG9ydCByZWxlYXNlZCBldmVyeSB5ZWFyIHRvIGNvbW11bmljYXRlIHRoZSBpbXBhY3Qgb2YgYWlyIHBvbGx1dGlvbiBvbiBwdWJsaWMgaGVhbHRoLiAKClRoZSBbU3RhdGUgb2YgR2xvYmFsIEFpciAyMDE5IHJlcG9ydF0oaHR0cHM6Ly93d3cuc3RhdGVvZmdsb2JhbGFpci5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9zb2dhXzIwMTlfcmVwb3J0LnBkZil7dGFyZ2V0PSJfYmxhbmsifQp3aGljaCB1c2VzIGRhdGEgZnJvbSAyMDE3IHN0YXRlZCB0aGF0OgoKPiBBaXIgcG9sbHV0aW9uIGlzIHRoZSAqKmZpZnRoKiogbGVhZGluZyByaXNrIGZhY3RvciBmb3IgbW9ydGFsaXR5IHdvcmxkd2lkZS4gSXQgaXMgcmVzcG9uc2libGUgZm9yIG1vcmUKZGVhdGhzIHRoYW4gbWFueSBiZXR0ZXIta25vd24gcmlzayBmYWN0b3JzIHN1Y2ggYXMgbWFsbnV0cml0aW9uLCBhbGNvaG9sIHVzZSwgYW5kIHBoeXNpY2FsIGluYWN0aXZpdHkuCkVhY2ggeWVhciwgKiptb3JlKiogcGVvcGxlIGRpZSBmcm9tIGFpciBwb2xsdXRpb27igJNyZWxhdGVkIGRpc2Vhc2UgdGhhbiBmcm9tIHJvYWQgKip0cmFmZmljIGluanVyaWVzKiogb3IgKiptYWxhcmlhKiouCgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI2MDAiIHNyYz0iaHR0cHM6Ly93d3cuaGVhbHRoZWZmZWN0cy5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9Tb0dBLUZpZ3VyZXMtMDEuanBnIj4KPC9wPgoKVGhlIHJlcG9ydCBhbHNvIHN0YXRlZCB0aGF0OgoKPkluIDIwMTcsIGFpciBwb2xsdXRpb24gaXMgZXN0aW1hdGVkIHRvIGhhdmUgY29udHJpYnV0ZWQgdG8gY2xvc2UgdG8gNSBtaWxsaW9uCmRlYXRocyBnbG9iYWxseSDigJQgbmVhcmx5ICoqMSBpbiBldmVyeSAxMCBkZWF0aHMqKi4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCIyMDE3ZGVhdGhzLnBuZyIpKQpgYGAKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5zdGF0ZW9mZ2xvYmFsYWlyLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL3NvZ2FfMjAxOV9mYWN0X3NoZWV0LnBkZikKClRoZSBbU3RhdGUgb2YgR2xvYmFsIEFpciAyMDE4IHJlcG9ydF0oaHR0cHM6Ly93d3cuc3RhdGVvZmdsb2JhbGFpci5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9zb2dhLTIwMTgtcmVwb3J0LnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgdXNpbmcgZGF0YSBmcm9tIDIwMTYgd2hpY2ggc2VwYXJhdGVkIGRpZmZlcmVudCB0eXBlcyBvZiBhaXIgcG9sbHV0aW9uLCBmb3VuZCB0aGF0ICoqcGFydGljdWxhdGUgcG9sbHV0aW9uIHdhcyBwYXJ0aWN1bGFybHkgYXNzb2NpYXRlZCB3aXRoIG1vcnRhbGl0eSoqLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsIjIwMTdtb3J0YWxpdHkucG5nIikpCmBgYAoKVGhlIDIwMTkgcmVwb3J0IHNob3dzIHRoYXQgdGhlIGhpZ2hlc3QgbGV2ZWxzIG9mIGZpbmUgcGFydGljdWxhdGUgcG9sbHV0aW9uIG9jY3VycyBpbiBBZnJpY2EgYW5kIEFzaWEgYW5kIHRoYXQ6Cgo+IE1vcmUgdGhhbiAqKjkwJSoqIG9mIHBlb3BsZSB3b3JsZHdpZGUgbGl2ZSBpbiBhcmVhcyAqKmV4Y2VlZGluZyoqIHRoZSBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIChXSE8pICoqR3VpZGVsaW5lKiogZm9yIGhlYWx0aHkgYWlyLiBNb3JlIHRoYW4gaGFsZiBsaXZlIGluIGFyZWFzIHRoYXQgZG8gbm90IGV2ZW4gbWVldCBXSE/igJlzIGxlYXN0LXN0cmluZ2VudCBhaXIgcXVhbGl0eSB0YXJnZXQuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwiUE13b3JsZC5wbmciKSkKYGBgCgpMb29raW5nIGF0IHRoZSBVUyBzcGVjaWZpY2FsbHksIGFpciBwb2xsdXRpb24gbGV2ZWxzIGFyZSBnZW5lcmFsbHkgaW1wcm92aW5nLiBUaGUgVVMgRW52aXJvbm1lbnRhbCBQcm90ZWN0aW9uIEFnZW5jeSAoRVBBKSBhbHNvIHJlbGVhc2VzIGEgcmVwb3J0IGFib3V0IGFpciBwb2xsdXRpb24gbGV2ZWxzIGNhbGxlZCBbKk91ciBOYXRpb24ncyBBaXIqXShodHRwczovL2dpc3B1Yi5lcGEuZ292L2Fpci90cmVuZHNyZXBvcnQvMjAxOS8jaG9tZSl7dGFyZ2V0PSJfYmxhbmsifS4KCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJVUy5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vZ2lzcHViLmVwYS5nb3YvYWlyL3RyZW5kc3JlcG9ydC8yMDE5L2RvY3VtZW50YXRpb24vQWlyVHJlbmRzX0ZseWVyLnBkZikKCkhvd2V2ZXIsIGFpciBwb2xsdXRpb24gKipjb250aW51ZXMgdG8gY29udHJpYnV0ZSB0byBoZWFsdGggcmlzayBmb3IgQW1lcmljYW5zKiosIGluIHBhcnRpY3VsYXIgaW4gKipyZWdpb25zIHdpdGggaGlnaGVyIHRoYW4gbmF0aW9uYWwgYXZlcmFnZSByYXRlcyoqIG9mIHBvbGx1dGlvbiB0aGF0IGFjdHVhbGx5IGF0IHRpbWUgZXhjZWVkIHRoZSB3b3JsZCBoZWFsdGggb3JnYW5pemF0aW9uJ3MgcmVjb21tZW5kZWQgbGV2ZWwuIFRodXMgaXQgaXMgbmVjZXNzYXJ5IHRvIG9idGFpbiBoaWdoIHNwYXRpYWwgZ3JhbnVsYXJpdHkgaW4gZXN0aW1hdGVzIG9mIGFpciBwb2xsdXRpb24gaW4gb3JkZXIgdG8gaWRlbnRpZnkgbG9jYXRpb25zIHdoZXJlIHBvcHVsYXRpb25zIGFyZSBleHBlcmllbmNpbmcgaGFybWZ1bCBsZXZlbHMgb2YgZXhwb3N1cmUuCgoKWW91IGNhbiBzZWUgdGhhdCBjdXJyZW50IGFpciBxdWFsaXR5IGNvbmRpdGlvbnMgYXQgdGhpcyBbd2Vic2l0ZV0oaHR0cHM6Ly9hcWljbi5vcmcvY2l0eS91c2EvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB5b3Ugd2lsbCBub3RpY2UgdmFyaWF0aW9uIGFjcm9zcyBkaWZmZXJlbnQgY2l0aWVzLgoKSGVyZSB3ZXJlIHRoZSBjb25kaXRpb25zIGluIFRvcGVrYSBLYW5zYXMgd2hlbiB0aGlzIHdhcyB3cml0dGVuOgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkthbnNhcy5wbmciKSkKYGBgCgpJdCByZXBvcnRzIHBhcnRpY3VsYXRlIHZhbHVlcyB1c2luZyB3aGF0IGlzIGNhbGxlZCB0aGUgW0FpciBRdWFsaXR5IEluZGV4XShodHRwczovL3d3dy5haXJub3cuZ292L2luZGV4LmNmbT9hY3Rpb249YXFpYmFzaWNzLmFxaSl7dGFyZ2V0PSJfYmxhbmsifSBzY2FsZSAoQVFJKSwgdGhpcyBbY2FsY3VsYXRvcl0oaHR0cHM6Ly9haXJub3cuZ292L2luZGV4LmNmbT9hY3Rpb249YWlybm93LmNhbGN1bGF0b3Ipe3RhcmdldD0iX2JsYW5rIn0gaW5kaWNhdGVzIHRoYXQgMTE0IEFRSSBpcyBlcXVpdmFsZW50IHRvIDQwLjcgdWcvbV4zXiBhbmQgaXMgY29uc2lkZXJlZCB1bmhlYWx0aHkgZm9yIHNlbnNpdGl2ZSBpbmRpdmlkdWFscy4gVGh1cyBzb21lIGFyZWFzIHZlcnkgbXVjaCBleGNlZWQgdGhlIFdvcmxkIEhlYWx0aCBPcmdhbml6YXRpb24gKFdITykgIGFubnVhbCBleHBvc3VyZSBndWlkZWxpbmUgKDEwIHVnL21eM14pIGF0IGNlcnRhaW4gdGltZXMgYW5kIHRoaXMgbWF5IGFkdmVyc2VseSBhZmZlY3QgdGhlIGhlYWx0aCBvZiBwZW9wbGUgbGl2aW5nIGluIHRoZXNlIGxvY2F0aW9ucy4KCkZ1cnRoZXJtb3JlLCBhZHZlcnNlIGhlYWx0aCBlZmZlY3RzIGhhdmUgYmVlbiBhc3NvY2lhdGVkIHdpdGggcG9wdWxhdGlvbnMgZXhwZXJpZW5jaW5nIGhpZ2hlciBwb2xsdXRpb24gZXhwb3N1cmUgZGVzcGl0ZSB0aGUgbGV2ZWxzIGJlaW5nIGJlbG93IHN1Z2dlc3RlZCBndWlkZWxpbmVzLiBTZWNvbmRseSwgaXQgYXBwZWFycyB0aGF0IHRoZSBjb21wb3NpdGlvbiBvZiB0aGUgcGFydGljdWxhdGUgbWF0ZXIgYW5kIHRoZSBpbmZsdWVuY2Ugb2Ygb3RoZXIgZGVtb2dyYXBoaWMgZmFjdG9ycyBtYXkgbWFrZSBzcGVjaWZpYyBwb3B1bGF0aW9ucyBtb3JlIGF0IHJpc2sgZm9yIGFkdmVyc2UgaGVhbHRoIGVmZmVjdHMgZHVlIHRvIGFpciBwb2xsdXRpb24uIFNlZSB0aGlzIFthcnRpY2xlXShodHRwczovL3d3dy5uZWptLm9yZy9kb2kvZnVsbC8xMC4xMDU2L05FSk1vYTE3MDI3NDcpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgZGV0YWlscy4KClRoZSBtb25pdG9yIGRhdGEgdGhhdCB3ZSB3aWxsIHVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgY29tZXMgZnJvbSBhIHN5c3RlbSBvZiBtb25pdG9ycyBpbiB3aGljaCByb3VnaGx5IDkwJSBhcmUgbG9jYXRlZCB3aXRoaW4gY2l0aWVzLiBUaHVzIHRoZXJlIGlzIGFuICoqZXF1aXR5IGlzc3VlKiogaW4gdGVybXMgb2YgY2FwdHVyaW5nIHRoZSBhaXIgcG9sbHV0aW9uIGxldmVscyBvZiBtb3JlIHJ1cmFsIGFyZWFzLiBUaGVyZWZvcmUsIHRvIGdldCBhIGJldHRlciBzZW5zZSBvZiB0aGUgcG9sbHV0aW9uIGV4cG9zdXJlcyBmb3IgdGhlIGluZGl2aWR1YWxzIGxpdmluZyBpbiB0aGVzZSBhcmVhcywgbWV0aG9kcyBsaWtlIG1hY2hpbmUgbGVhcm5pbmcgY2FuIGJlIHZlcnkgdXNlZnVsIHRvIGVzdGltYXRlIGFpciBwb2xsdXRpb24gbGV2ZWxzIGluICoqYXJlYXMgd2l0aCBsaXR0bGUgdG8gbm8gbW9uaXRvcmluZyoqLgoKSW5kZWVkLCBtYWNoaW5lIGxlYXJuaW5nIG1ldGhvZHMgYXJlIGluIGZhY3QgdXNlZCB0byBiZSBhYmxlIHRvIGVzdGltYXRlIGFpciBwb2xsdXRpb24gaW4gdGhlc2UgbG93IG1vbml0b3JpbmcgYXJlYXMgc28gdGhhdCB3ZSBjYW4gbWFrZSBhIG1hcCBsaWtlIHRoaXMgd2hlcmUgd2UgaGF2ZSBhbm51YWwgZXN0aW1hdGVzIGZvciBhbGwgb2YgdGhlIGNvbnRpZ3VvdXMgVVM6Cgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI2MDAiIHNyYz0iaHR0cHM6Ly9hcmMtYW5nbGVyZmlzaC13YXNocG9zdC1wcm9kLXdhc2hwb3N0LnMzLmFtYXpvbmF3cy5jb20vcHVibGljL1NBV09FR0JYTVZHUTdBUzVQWjZVVU9YNkZZLnBuZyI+CjwvcD4KCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vdXJsP3NhPWkmdXJsPWh0dHBzJTNBJTJGJTJGd3d3Lndhc2hpbmd0b25wb3N0LmNvbSUyRmJ1c2luZXNzJTJGMjAxOSUyRjEwJTJGMjMlMkZhaXItcG9sbHV0aW9uLWlzLWdldHRpbmctd29yc2UtZGF0YS1zaG93LW1vcmUtcGVvcGxlLWFyZS1keWluZyUyRiZwc2lnPUFPdlZhdzN2LVpEVEJQbkxQMk1ZdEtmM1VuZGomdXN0PTE1ODU3ODQ0NzkwNjgwMDAmc291cmNlPWltYWdlcyZjZD12ZmUmdmVkPTBDQUlRalJ4cUZ3b1RDUEN5bjlmeHhlZ0NGUUFBQUFBZEFBQUFBQkFkKQoKVGhpcyBpcyB3aGF0IHdlIGFpbSB0byBhY2hpZXZlIGluIHRoaXMgY2FzZSBzdHVkeS4KCiMjIyBMaW1pdGF0aW9ucwoKVGhlcmUgYXJlIHNvbWUgaW1wb3J0YW50IGNvbnNpZGVyYXRpb25zIHJlZ2FyZGluZyB0aGlzIGRhdGEgYW5hbHlzaXMgdG8ga2VlcCBpbiBtaW5kOiAKCjEpIFRoZSBkYXRhIGluIG91ciBhbmFseXNpcyBkb2VzIG5vdCBpbmNsdWRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjb21wb3NpdGlvbiBvZiBwYXJ0aWN1bGF0ZSBtYXRlci4gRGlmZmVyZW50IHR5cGVzIG9mIHBhcnRpY3VsYXRlcyBtYXkgYmUgbW9yZSBiZW5pZ24gb3IgZGVsZXRlcmlvdXMgZm9yIGhlYWx0aCBvdXRjb21lcy4KCjIpIE91dGRvb3IgcG9sbHV0aW9uIGxldmVscyBhcmUgbm90IG5lY2Vzc2FyaWx5IGFuIGluZGljYXRpb24gb2Ygb2YgaW5kaXZpZHVhbCBleHBvc3VyZXMuIFBlb3BsZSBzcGVuZCBkaWZmZXJpbmcgYW1vdW50cyBvZiB0aW1lIGluZG9vcnMgYW5kIG91dGRvb3JzIGFuZCBhcmUgZXhwb3NlZCB0byBkaWZmZXJlbnQgcG9sbHV0aW9uIGxldmVscyBpbmRvb3JzLiBQZW9wbGUgYXJlIG5vdyBkZXZlbG9waW5nIHBlcnNvbmFsIG1vbml0b3Jpbmcgc3lzdGVtcyB0byB0cmFjayBhaXIgcG9sbHV0aW9uIGxldmVscyBvbiB0aGUgcGVyc29uYWwgbGV2ZWwuCgpPdXIgYW5hbHlzaXMgd2lsbCB1c2UgYW5udWFsIG1lYW4gZXN0aW1hdGVzLCBob3dldmVyIHBvbGx1dGlvbiBsZXZlbHMgY2FuIHZhcnkgZ3JlYXRseSBieSBzZWFzb24sIGRheSBhbmQgZXZlbiBob3VyLiBUaGVyZSBhcmUgZGF0YSBzb3VyY2VzIHRoYXQgaGF2ZSBmaW5lciBsZXZlbHMgb2YgdGVtcG9yYWwgZGF0YSwgaG93ZXZlciB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBsb25nIHRlcm0gZXhwb3N1cmVzLCBhcyB0aGVzZSBhcHBlYXIgdG8gYmUgdGhlIG1vc3QgaW5mbHVlbnRpYWwgZm9yIGhlYWx0aCBvdXRjb21lcywgc28gd2UgY2hvc2UgdG8gdXNlIGFubnVhbCBsZXZlbCBkYXRhLiAKCgojIyBXaGF0IGFyZSB0aGUgZGF0YT8KCkluIE1hY2hpbmUgTGVhcm5pbmcgZm9yIHByZWRpY3Rpb24sIHRoZXJlIGFyZSB0d28gbWFpbiB0eXBlcyBvZiB2YXJpYWJsZXM6CgoxKSBPdXRjb21lIHZhcmlhYmxlCjIpIFByZWRpY3RvciB2YXJpYWJsZXMKClRoZSAqKm91dGNvbWUgdmFyaWFibGUqKiBpcyB3aGF0IGFyZSB0cnlpbmcgdG8gKipwcmVkaWN0KiouIEluIGJ1aWxkaW5nIG91ciBtb2RlbCB3ZSBhY3R1YWxseSBoYXZlIHRoZSBvdXRjb21lIHZhcmlhYmxlIGRhdGEsIGJ1dCB3ZSB3YW50IHRvIHNlZSBob3cgd2VsbCBvdXIgcHJlZGljdG9yIHZhcmlhYmxlcyBjYW4gZXhwbGFpbiB0aGUgdmFyaWF0aW9uIGluIG91ciBvdXRjb21lIGRhdGEuIFRoaXMgZ2l2ZXMgdXMgYSBzZW5zZSBvZiBob3cgd2VsbCB3ZSBjYW4gdXNlIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgZGF0YSB0byBwcmVkaWN0IG91ciBvdXRjb21lIHZhcmlhYmxlIGxldmVscyB3aGVuIHdlIGluIGZhY3QgZG8gbm90IGhhdmUgZGF0YSBhYm91dCB0aGUgb3V0Y29tZS4KCkFzIGEgc2ltcGxlciBleGFtcGxlLCBpbWFnaW5lIHRoYXQgd2UgaGF2ZSBkYXRhIGFib3V0IHRoZSBzYWxlcyBhbmQgY2hhcmFjdGVyaXN0aWNzIG9mIGNhcnMgZnJvbSBsYXN0IHllYXIgYW5kIHdlIHdhbnQgdG8gcHJlZGljdCB3aGljaCBjYXJzIG1pZ2h0IHNlbGwgd2VsbCB0aGlzIHllYXIuIFdlIGRvIG5vdCBoYXZlIHRoZSBzYWxlcyBkYXRhIHlldCBmb3IgdGhpcyB5ZWFyLCBidXQgd2UgZG8ga25vdyB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIG91ciBjYXJzIGZvciB0aGlzIHllYXIuIFdlIGNhbiB1c2UgYSBtb2RlbCBvZiB0aGUgY2hhcmFjdGVyaXN0aWNzIHRoYXQgZXhwbGFpbmVkIHNhbGVzIGxhc3QgeWVhciB0byBlc3RpbWF0ZSB3aGF0IGNhcnMgbWlnaHQgc2VsbCB3ZWxsIHRoaXMgeWVhci4gSW4gdGhpcyBjYXNlLCBvdXIgb3V0Y29tZSB2YXJpYWJsZSBpcyB0aGUgc2FsZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2Fycywgd2hpbGUgdGhlIGRpZmZlcmVudCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIGNhcnMgbWFrZSB1cCBvdXIgcHJlZGljdG9yIG9yIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4KCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBldmFsdWF0ZSBhaXIgcG9sbHV0aW9uIG1vbml0b3IgZGF0YSBvZiBmaW5lIHBhcnRpY3VsYXRlIG1hdGVyIChQTX4yLjV+KSBpbiB0aGUgY29udGlndW91cyBVUyBmcm9tIDIwMDgsIGFzIHdlbGwgYXMgZGF0YSBhYm91dCBwb3B1bGF0aW9uIGRlbnNpdHksIHJvYWQgZGVuc2l0eSwgdXJiYW5pemF0aW9uIGxldmVscywgYW5kIE5BU0Egc2F0ZWxsaXRlIGRhdGEgdG8gZGV2ZWxvcCBtb2RlbHMgdG8gcHJlZGljdCBsb2NhbGl6ZWQgYWlyIHBvbGx1dGlvbiBsZXZlbHMuIAoKVGhlIG1vbml0b3IgZGF0YSB3aWxsIGJlIG91ciAqKm91dGNvbWUgdmFyaWFibGUqKi4gIFdlIHdhbnQgdG8gZGV0ZXJtaW5lIGlmIHdlIGNhbiAqKnByZWRpY3QqKiBhaXIgcG9sbHV0aW9uIGxldmVscyBiYXNlZCBvbiBvdGhlciB0eXBlcyBvZiBkYXRhLCBsaWtlIHJvYWQgZGVuc2l0eSBhbmQgcG9wdWxhdGlvbiBkZW5zaXR5IHRvIHNlZSBpZiB3ZSBjYW4gdXNlIHRoZXNlIGRhdGEgdG8gcHJlZGljdCBhaXIgcG9sbHV0aW9uIGluIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBubyBtb25pdG9ycy4gCgoKIyMjIE91ciBvdXRjb21lIHZhcmlhYmxlCgpUaGUgbW9uaXRvciBkYXRhIHRoYXQgd2Ugd2lsbCBiZSB1c2luZyBjb21lcyBmcm9tICoqW2dyYXZpbWV0cmljIG1vbml0b3JzXShodHRwczovL3B1YmxpY2xhYi5vcmcvd2lraS9maWx0ZXItcG0pe3RhcmdldD0iX2JsYW5rIn0qKiBvcGVyYXRlZCBieSB0aGUgVVMgW0VuaXZvcm5tZW50YWwgUHJvdGVjdGlvbiBBZ2VuY3kgKEVQQSldKGh0dHBzOi8vd3d3LmVwYS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGVzZSBtb25pdG9ycyB1c2UgYSBmaWx0cmF0aW9uIHN5c3RlbSB0byBzcGVjaWZpY2FsbHkgY2FwdHVyZSBmaW5lIHBhcnRpY3VsYXRlIG1hdHRlci4gVGhlIHdlaWdodCBvZiB0aGlzIG1hdHRlciBpcyBtYW51YWxseSBtZWFzdXJlZCBkYWlseSBvciB3ZWVrbHkuIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3czLmVwYS5nb3YvdHRuYW10aTEvZmlsZXMvYW1iaWVudC9wbTI1L3NwZWMvUlRJR3Jhdk1hc3NTT1BGSU5BTC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gZm9yIHRoZSBFUEEgc3RhbmRhcmQgb3BlcmF0aW5nIHByb2NlZHVyZSBmb3IgUE0gZ3JhdmltZXRyaWMgYW5hbHlzaXMgaW4gMjAwOC4KCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSIxNTBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsImZpbHRlci5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly9wdWJsaWNsYWIub3JnL3dpa2kvZmlsdGVyLXBtKV0KCkhlcmUgaXMgYW4gaW1hZ2Ugb2Ygd2hhdCB0aGUgZ3JhdmltZXRyaWMgbW9uaXRvcnMgbG9vayBsaWtlOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSIxMDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsIm1vbml0b3IucG5nIikpCmBgYAoKCkdyYXZpbWV0cmljIGFuYWx5c2lzIGlzIGFsc28gdXNlZCBmb3IgW2VtaXNzaW9uIHRlc3RpbmddKGh0dHBzOi8vd3d3Lm10LmNvbS91cy9lbi9ob21lL2FwcGxpY2F0aW9ucy9MYWJvcmF0b3J5X3dlaWdoaW5nL2VtaXNzaW9ucy10ZXN0aW5nLXBhcnRpY3VsYXRlLW1hdHRlci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGUgc2FtZSBpZGVhIGFwcGxpZXM6IGEgZnJlc2ggZmlsdGVyIGlzIGFwcGxpZWQgYW5kIHRoZSBkZXNpcmVkIGFtb3VudCBvZiB0aW1lIHBhc3NlcywgdGhlbiB0aGUgZmlsdGVyIGlzIHJlbW92ZWQgYW5kIHdlaWdoZWQuIAoKVGhlcmUgYXJlIFtvdGhlciBtb25pdG9yaW5nIHN5c3RlbXNdKGh0dHBzOi8vd3d3LnNlbnNpcmlvbi5jb20vZW4vYWJvdXQtdXMvbmV3c3Jvb20vc2Vuc2lyaW9uLXNwZWNpYWxpc3QtYXJ0aWNsZXMvcGFydGljdWxhdGUtbWF0dGVyLXNlbnNpbmctZm9yLWFpci1xdWFsaXR5LW1lYXN1cmVtZW50cy8pe3RhcmdldD0iX2JsYW5rIn0gdGhhdCBjYW4gcHJvdmlkZSBob3VybHkgbWVhc3VyZW1lbnRzLCBidXQgd2Ugd2lsbCBub3QgYmUgdXNpbmcgZGF0YSBmcm9tIHRoZXNlIG1vbml0b3JzIGluIG91ciBhbmFseXNpcy4gR3JhdmltZXRyaWMgYW5hbHlzaXMgaXMgY29uc2lkZXJlZCB0byBiZSBhbW9uZyB0aGUgbW9zdCBhY2N1cmF0ZSBtZXRob2RzLgoKSW4gb3VyIGNzdiwgdGhlICoqdmFsdWUqKiBjb2x1bW4gaW5kaWNhdGVzIHRoZSBQTX4yLjV+IG1vbml0b3IgYXZlcmFnZSBmb3IgMjAwOCBpbiBtYXNzIG9mIGZpbmUgcGFydGljbGVzL3ZvbHVtZSBvZiBhaXIgZm9yIDg3NiBncmF2aW1ldHJpYyBtb25pdG9ycy4gVGhlIHVuaXRzIGFyZSBtaWNybyBncmFtcyBvZiBmaW5lIHBhcnRpY3VsYXRlIG1hdGVyIChQTSkgdGhhdCBpcyBsZXNzIHRoYW4gMi41IG1pY3JvbWV0ZXJzIGluIGRpYW1ldGVyIHBlciBjdWJpYyBtZXRlciBvZiBhaXIgLSBtYXNzIGNvbmNlbnRyYXRpb24gKHVnL21eM14pLiAgUmVjYWxsIHRoZSB0aGUgV0hPIGV4cG9zdXJlICBndWlkZWxpbmUgaXMgPCAxMCB1Zy9tXjNeIG9uIGF2ZXJhZ2UgYW5udWFsbHkgZm9yIFBNfjIuNX4uCgojIyMgT3VyIHByZWRpY3RvciB2YXJpYWJsZXMKClRoZXJlIGFyZSA0OCBwcmVkaWN0b3IgdmFyaWFibGVzIHdpdGggdmFsdWVzIGZvciBlYWNoIG9mIHRoZSA4NzYgbW9uaXRvcnMgaW5jbHVkZWQgaW4gb3VyIG91dGNvbWUgdmFyaWFibGUuIFRoZSBkYXRhIGNvbWVzIGZyb20gdGhlIFVTIFtFbml2b3JubWVudGFsIFByb3RlY3Rpb24gQWdlbmN5IChFUEEpXShodHRwczovL3d3dy5lcGEuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifSwgdGhlIFtOYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24gKE5BU0EpXShodHRwczovL3d3dy5uYXNhLmdvdi8pe3RhcmdldD0iX2JsYW5rIn0sIHRoZSBVUyBbQ2Vuc3VzXShodHRwczovL3d3dy5jZW5zdXMuZ292L2Fib3V0L3doYXQvY2Vuc3VzLWF0LWEtZ2xhbmNlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0sIGFuZCB0aGUgW05hdGlvbmFsIENlbnRlciBmb3IgSGVhbHRoIFN0YXRpc3RpY3MgKE5DSFMpXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvYWJvdXQvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9LgoKVmFyaWFibGUgICB8IERldGFpbHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoqKmlkKiogIHwgTW9uaXRvciBudW1iZXIgIDxicj4gLS0gdGhlIGNvdW50eSBudW1iZXIgaXMgaW5kaWNhdGVkIGJlZm9yZSB0aGUgZGVjaW1hbCA8YnI+IC0tIHRoZSBtb25pdG9yIG51bWJlciBpcyBpbmRpY2F0ZWQgYWZ0ZXIgdGhlIGRlY2ltYWwgPGJyPiAgKipFeGFtcGxlKio6IDEwNzMuMDAyMyAgaXMgSmVmZmVyc29uIGNvdW50eSAoMTA3MykgYW5kIC4wMDIzIG9uZSBvZiA4IG1vbml0b3JzIAoqKmZpcHMqKiB8IEZlZGVyYWwgaW5mb3JtYXRpb24gcHJvY2Vzc2luZyBzdGFuZGFyZCBudW1iZXIgZm9yIHRoZSBjb3VudHkgd2hlcmUgdGhlIG1vbml0b3IgaXMgbG9jYXRlZCA8YnI+IC0tIDUgZGlnaXQgaWQgY29kZSBmb3IgY291bnRpZXMgKHplcm8gaXMgb2Z0ZW4gdGhlIGZpcnN0IHZhbHVlIGFuZCBzb21ldGltZXMgaXMgbm90IHNob3duKSA8YnI+IC0tIHRoZSBmaXJzdCAyIG51bWJlcnMgaW5kaWNhdGUgdGhlIHN0YXRlIDxicj4gLS0gdGhlIGxhc3QgdGhyZWUgbnVtYmVycyBpbmRpY2F0ZSB0aGUgY291bnR5IDxicj4gICoqRXhhbXBsZSoqOiBBbGFiYW1hJ3Mgc3RhdGUgY29kZSBpcyAwMSBiZWNhdXNlIGl0IGlzIGZpcnN0IGFscGhhYmV0aWNhbGx5IDxicj4gKG5vdGU6IEFsYXNrYSBhbmQgSGF3YWlpIGFyZSBub3QgaW5jbHVkZWQgYmVjYXVzZSB0aGV5IGFyZSBub3QgcGFydCBvZiB0aGUgY29udGlndW91cyBVUykgIAoqKkxhdCoqIHwgTGF0aXR1ZGUgb2YgdGhlIG1vbml0b3IgaW4gZGVncmVlcyAgCioqTG9uKiogfCBMb25naXR1ZGUgb2YgdGhlIG1vbml0b3IgaW4gZGVncmVlcyAgCioqc3RhdGUqKiB8IFN0YXRlIHdoZXJlIHRoZSBtb25pdG9yIGlzIGxvY2F0ZWQKKipjb3VudHkqKiB8IENvdW50eSB3aGVyZSB0aGUgbW9uaXRvciBpcyBsb2NhdGVkCioqY2l0eSoqIHwgQ2l0eSB3aGVyZSB0aGUgbW9uaXRvciBpcyBsb2NhdGVkCioqQ01BUSoqICB8IEVzdGltYXRlZCB2YWx1ZXMgb2YgYWlyIHBvbGx1dGlvbiBmcm9tIGEgY29tcHV0YXRpb25hbCBtb2RlbCBjYWxsZWQgWyoqQ29tbXVuaXR5IE11bHRpc2NhbGUgQWlyIFF1YWxpdHkgKENNQVEpKipdKGh0dHBzOi8vd3d3LmVwYS5nb3YvY21hcSl7dGFyZ2V0PSJfYmxhbmsifSA8YnI+IC0tICBBIG1vbml0b3Jpbmcgc3lzdGVtIHRoYXQgc2ltdWxhdGVzIHRoZSBwaHlzaWNzIG9mIHRoZSBhdG1vc3BoZXJlIHVzaW5nIGNoZW1pc3RyeSBhbmQgd2VhdGhlciBkYXRhIHRvIHByZWRpY3QgdGhlIGFpciBwb2xsdXRpb24gPGJyPiAtLSAqKipEb2VzIG5vdCB1c2UgYW55IG9mIHRoZSBQTX4yLjV+IGdyYXZpbWV0cmljIG1vbml0b3JpbmcgZGF0YS4qKiogKFRoZXJlIGlzIGEgdmVyc2lvbiB0aGF0IGRvZXMgdXNlIHRoZSBncmF2aW1ldHJpYyBtb25pdG9yaW5nIGRhdGEsIGJ1dCBub3QgdGhpcyBvbmUhKSA8YnI+IC0tIERhdGEgZnJvbSB0aGUgRVBBCioqemN0YSoqIHwgW1ppcCBDb2RlIFRhYnVsYXRpb24gQXJlYV0oaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvZ2VvL3BkZnMvZWR1Y2F0aW9uL2Jyb2NodXJlcy9aQ1RBcy5wZGYpe3RhcmdldD0iX2JsYW5rIn0gd2hlcmUgdGhlIG1vbml0b3IgaXMgbG9jYXRlZCA8YnI+IC0tIFBvc3RhbCBaaXAgY29kZXMgYXJlIGNvbnZlcnRlZCBpbnRvICJnZW5lcmFsaXplZCBhcmVhbCByZXByZXNlbnRhdGlvbnMiIHRoYXQgYXJlIG5vbi1vdmVybGFwcGluZyAgPGJyPiAtLSBEYXRhIGZyb20gdGhlIDIwMTAgQ2Vuc3VzICAKKip6Y3RhX2FyZWEqKiB8IExhbmQgYXJlYSBvZiB0aGUgemlwIGNvZGUgYXJlYSBpbiBtZXRlcnMgc3F1YXJlZCAgPGJyPiAtLSBEYXRhIGZyb20gdGhlIDIwMTAgQ2Vuc3VzICAKKip6Y3RhX3BvcCoqIHwgUG9wdWxhdGlvbiBpbiB0aGUgemlwIGNvZGUgYXJlYSAgPGJyPiAtLSBEYXRhIGZyb20gdGhlIDIwMTAgQ2Vuc3VzICAKKippbXBfYTUwMCoqIHwgSW1wZXJ2aW91cyBzdXJmYWNlIG1lYXN1cmUgPGJyPiAtLSBXaXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiA1MDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciA8YnI+IC0tIEltcGVydmlvdXMgc3VyZmFjZSBhcmUgcm9hZHMsIGNvbmNyZXRlLCBwYXJraW5nIGxvdHMsIGJ1aWxkaW5ncyA8YnI+IC0tIFRoaXMgaXMgYSBtZWFzdXJlIG9mIGRldmVsb3BtZW50IAoqKmltcF9hMTAwMCoqIHwgSW1wZXJ2aW91cyBzdXJmYWNlIG1lYXN1cmUgPGJyPiAtLSAgV2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yCioqaW1wX2E1MDAwKiogfCBJbXBlcnZpb3VzIHN1cmZhY2UgbWVhc3VyZSA8YnI+IC0tICBXaXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiA1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgIAoqKmltcF9hMTAwMDAqKiB8IEltcGVydmlvdXMgc3VyZmFjZSBtZWFzdXJlIDxicj4gLS0gIFdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDEwMDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgICAKKippbXBfYTE1MDAwKiogfCBJbXBlcnZpb3VzIHN1cmZhY2UgbWVhc3VyZSA8YnI+IC0tICBXaXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxNTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yICAKKipjb3VudHlfYXJlYSoqIHwgTGFuZCBhcmVhIG9mIHRoZSBjb3VudHkgb2YgdGhlIG1vbml0b3IgaW4gbWV0ZXJzIHNxdWFyZWQgIAoqKmNvdW50eV9wb3AqKiB8IFBvcHVsYXRpb24gb2YgdGhlIGNvdW50eSBvZiB0aGUgbW9uaXRvciAgCioqTG9nX2Rpc3RfdG9fcHJpc2VjKiogfCBMb2cgKE5hdHVyYWwgbG9nKSBkaXN0YW5jZSB0byBhIHByaW1hcnkgb3Igc2Vjb25kYXJ5IHJvYWQgZnJvbSB0aGUgbW9uaXRvciA8YnI+IC0tIEhpZ2h3YXkgb3IgbWFqb3Igcm9hZCAgCioqbG9nX3ByaV9sZW5ndGhfNTAwMCoqIHwgQ291bnQgb2YgcHJpbWFyeSByb2FkIGxlbmd0aCBpbiBtZXRlcnMgaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiA1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSA8YnI+IC0tIEhpZ2h3YXlzIG9ubHkgIAoqKmxvZ19wcmlfbGVuZ3RoXzEwMDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDEwMDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSA8YnI+IC0tIEhpZ2h3YXlzIG9ubHkgIAoqKmxvZ19wcmlfbGVuZ3RoXzE1MDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDE1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSA8YnI+IC0tIEhpZ2h3YXlzIG9ubHkgIAoqKmxvZ19wcmlfbGVuZ3RoXzI1MDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDI1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSA8YnI+IC0tIEhpZ2h3YXlzIG9ubHkgIAoqKmxvZ19wcmlzZWNfbGVuZ3RoXzUwMCoqIHwgQ291bnQgb2YgcHJpbWFyeSBhbmQgc2Vjb25kYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDUwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgIDxicj4gLS0gSGlnaHdheSBhbmQgc2Vjb25kYXJ5IHJvYWRzICAKKipsb2dfcHJpc2VjX2xlbmd0aF8xMDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgIDxicj4gLS0gSGlnaHdheSBhbmQgc2Vjb25kYXJ5IHJvYWRzICAKKipsb2dfcHJpc2VjX2xlbmd0aF81MDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgNTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgIDxicj4gLS0gSGlnaHdheSBhbmQgc2Vjb25kYXJ5IHJvYWRzICAKKipsb2dfcHJpc2VjX2xlbmd0aF8xMDAwMCoqIHwgQ291bnQgb2YgcHJpbWFyeSBhbmQgc2Vjb25kYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDEwMDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgPGJyPiAtLSBIaWdod2F5IGFuZCBzZWNvbmRhcnkgcm9hZHMgIAoqKmxvZ19wcmlzZWNfbGVuZ3RoXzE1MDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTUwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICA8YnI+IC0tIEhpZ2h3YXkgYW5kIHNlY29uZGFyeSByb2FkcyAgCioqbG9nX3ByaXNlY19sZW5ndGhfMjUwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgYW5kIHNlY29uZGFyeSByb2FkIGxlbmd0aCBpbiBtZXRlcnMgaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAyNTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgIDxicj4gLS0gSGlnaHdheSBhbmQgc2Vjb25kYXJ5IHJvYWRzICAgICAgCioqbG9nX25laV8yMDA4X3BtMjVfc3VtXzEwMDAwKiogfCBUb25zIG9mIGVtaXNzaW9ucyBmcm9tIG1ham9yIHNvdXJjZXMgZGF0YSBiYXNlIChhbm51YWwgZGF0YSkgc3VtIG9mIGFsbCBzb3VyY2VzIHdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDEwMDAwIG1ldGVycyBvZiBkaXN0YW5jZSBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgICAKKipsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTUwMDAqKiB8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTUwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgICAKKipsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMjUwMDAqKiB8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMjUwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgICAKKipsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTAwMDAqKiB8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgICAgCioqbG9nX25laV8yMDA4X3BtMTBfc3VtXzE1MDAwKip8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTUwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgICAgCioqbG9nX25laV8yMDA4X3BtMTBfc3VtXzI1MDAwKiogfCBUb25zIG9mIGVtaXNzaW9ucyBmcm9tIG1ham9yIHNvdXJjZXMgZGF0YSBiYXNlIChhbm51YWwgZGF0YSkgc3VtIG9mIGFsbCBzb3VyY2VzIHdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDI1MDAwIG1ldGVycyBvZiBkaXN0YW5jZSBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgICAgIAoqKnBvcGRlbnNfY291bnR5KiogfCBQb3B1bGF0aW9uIGRlbnNpdHkgKG51bWJlciBvZiBwZW9wbGUgcGVyIGtpbG9tZXRlciBzcXVhcmVkIGFyZWEgb2YgdGhlIGNvdW50eSkKKipwb3BkZW5zX3pjdGEqKiB8IFBvcHVsYXRpb24gZGVuc2l0eSAobnVtYmVyIG9mIHBlb3BsZSBwZXIga2lsb21ldGVyIHNxdWFyZWQgYXJlYSBvZiB6Y3RhKQoqKm5vaHMqKiB8IFBlcmNlbnRhZ2Ugb2YgcGVvcGxlIGluIHpjdGEgYXJlYSB3aGVyZSB0aGUgbW9uaXRvciBpcyB0aGF0ICoqZG8gbm90IGhhdmUgYSBoaWdoIHNjaG9vbCBkZWdyZWUqKiA8YnI+IC0tIERhdGEgZnJvbSB0aGUgQ2Vuc3VzCioqc29tZWhzKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgKipzb21lIGhpZ2ggc2Nob29sIGVkdWNhdGlvbioqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMKKipocyoqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIHdob3NlIGhpZ2hlc3QgZm9ybWFsIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd2FzIGNvbXBsZXRpbmcgYSAqKmhpZ2ggc2Nob29sIGRlZ3JlZSoqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMgIAoqKnNvbWVjb2xsZWdlKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgY29tcGxldGluZyAqKnNvbWUgY29sbGVnZSBlZHVjYXRpb24qKiA8YnI+IC0tIERhdGEgZnJvbSB0aGUgQ2Vuc3VzIAoqKmFzc29jaWF0ZSoqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIHdob3NlIGhpZ2hlc3QgZm9ybWFsIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd2FzIGNvbXBsZXRpbmcgYW4gKiphc3NvY2lhdGUgZGVncmVlKiogPGJyPiAtLSBEYXRhIGZyb20gdGhlIENlbnN1cyAKKipiYWNoZWxvcioqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIHdob3NlIGhpZ2hlc3QgZm9ybWFsIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd2FzIGEgKipiYWNoZWxvcidzIGRlZ3JlZSoqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMgCioqZ3JhZCoqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIHdob3NlIGhpZ2hlc3QgZm9ybWFsIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd2FzIGEgKipncmFkdWF0ZSBkZWdyZWUqKiA8YnI+IC0tIERhdGEgZnJvbSB0aGUgQ2Vuc3VzIAoqKnBvdioqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIGlzIHRoYXQgbGl2ZWQgaW4gWyoqcG92ZXJ0eSoqXShodHRwczovL2FzcGUuaGhzLmdvdi8yMDA4LWhocy1wb3ZlcnR5LWd1aWRlbGluZXMpIGluIDIwMDggLSBvciB3b3VsZCBpdCBoYXZlIGJlZW4gMjAwNyBndWlkZWxpbmVzPz9odHRwczovL2FzcGUuaGhzLmdvdi8yMDA3LWhocy1wb3ZlcnR5LWd1aWRlbGluZXMgPGJyPiAtLSBEYXRhIGZyb20gdGhlIENlbnN1cyAgCioqaHNfb3JsZXNzKiogfCAgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIHdob3NlIGhpZ2hlc3QgZm9ybWFsIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgd2FzIGEgKipoaWdoIHNjaG9vbCBkZWdyZWUgb3IgbGVzcyoqIChzdW0gb2Ygbm9ocywgc29tZWhzLCBhbmQgaHMpICAKKip1cmMyMDEzKiogfCBbMjAxMyBVcmJhbi1ydXJhbCBjbGFzc2lmaWNhdGlvbl0oaHR0cHM6Ly93d3cuY2RjLmdvdi9uY2hzL2RhdGEvc2VyaWVzL3NyXzAyL3NyMDJfMTY2LnBkZil7dGFyZ2V0PSJfYmxhbmsifSBvZiB0aGUgY291bnR5IHdoZXJlIHRoZSBtb25pdG9yIGlzIGxvY2F0ZWQgPGJyPiAtLSA2IGNhdGVnb3J5IHZhcmlhYmxlIC0gMSBpcyB0b3RhbGx5IHVyYmFuIDYgaXMgY29tcGxldGVseSBydXJhbCA8YnI+ICAtLSBEYXRhIGZyb20gdGhlIE5hdGlvbmFsIENlbnRlciBmb3IgSGVhbHRoIFN0YXRpc3RpY3NdKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9pbmRleC5odG0pe3RhcmdldD0iX2JsYW5rIn0gICAgIAoqKnVyYzIwMDYqKiB8IFsyMDA2IFVyYmFuLXJ1cmFsIGNsYXNzaWZpY2F0aW9uXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvZGF0YS9zZXJpZXMvc3JfMDIvc3IwMl8xNTQucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IG9mIHRoZSBjb3VudHkgd2hlcmUgdGhlIG1vbml0b3IgaXMgbG9jYXRlZCA8YnI+IC0tIDYgY2F0ZWdvcnkgdmFyaWFibGUgLSAxIGlzIHRvdGFsbHkgdXJiYW4gNiBpcyBjb21wbGV0ZWx5IHJ1cmFsIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBbTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljc10oaHR0cHM6Ly93d3cuY2RjLmdvdi9uY2hzL2luZGV4Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifSAgICAgCioqYW9kKiogfCBBZXJvc29sIE9wdGljYWwgRGVwdGggbWVhc3VyZW1lbnQgZnJvbSBhIE5BU0Egc2F0ZWxsaXRlIDxicj4gLS0gYmFzZWQgb24gdGhlIGRlZnJhY3Rpb24gb2YgYSBsYXNlciA8YnI+IC0tIHVzZWQgYXMgYSBwcm94eSBvZiBwYXJ0aWN1bGF0ZSBwb2xsdXRpb24gPGJyPiAtLSB1bml0LWxlc3MgLSBoaWdoZXIgdmFsdWUgaW5kaWNhdGVzIG1vcmUgcG9sbHV0aW9uIDxicj4gLS0gRGF0YSBmcm9tIE5BU0EgIAoKTWFueSBvZiB0aGVzZSBwcmVkaWN0b3IgdmFyaWFibGVzIGhhdmUgdG8gZG8gd2l0aCB0aGUgY2lyY3VsYXIgYXJlYSBhcm91bmQgdGhlIG1vbml0b3IgY2FsbGVkIHRoZSAiYnVmZmVyIi4gVGhlc2UgYXJlIGlsbHVzdHJhdGVkIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMHB4Iix9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJyZWdyZXNzaW9uLnBuZyIpKQpgYGAKCiMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8xNTI5MjkwNildCgoKCiMjIERhdGEgSW1wb3J0CgpXZSBoYXZlIG9uZSBDU1YgZmlsZSB0aGF0IGNvbnRhaW5zIGJvdGggb3VyIHNpbmdsZSAqKm91dGNvbWUgdmFyaWFibGUqKiBhbmQgYWxsIG9mIG91ciAqKnByZWRpY3RvciB2YXJpYWJsZXMqKi4KCkxldCdzIGltcG9ydCBvdXIgZGF0YSBpbnRvIFIgbm93IHNvIHRoYXQgd2UgY2FuIGV4cGxvcmUgdGhlIGRhdGEgZnVydGhlci4gV2Ugd2lsbCBjYWxsIG91ciBkYXRhIG9iamVjdCBgcG1gIGZvciBwYXJ0aWN1bGF0ZSBtYXR0ZXIuCgpgYGB7cn0KcG0gPC1yZWFkcjo6cmVhZF9jc3YoaGVyZSgiZG9jcyIsICJwbTI1X2RhdGEuY3N2IikpCmBgYAoKIyMgRGF0YSBFeHBsb3JhdGlvbiBhbmQgV3JhbmdsaW5nCgpUaGUgZmlyc3Qgc3RlcCBpbiBwZXJmb3JtaW5nIGEgbWFjaGluZSBsZWFybmluZyBhbmFseXNpcyBpcyB0byBleHBsb3JlIHRoZSBkYXRhIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSB2YXJpYWJsZXMgIGluY2x1ZGVkIGluIHRoZSBkYXRhLCBhcyB3ZSBtYXkgbGVhcm4gYWJvdXQgaW1wb3J0YW50IGRldGFpbHMgYWJvdXQgdGhlIGRhdGEgdGhhdCB3ZSBzaG91bGQga2VlcCBpbiBtaW5kIGFzIHdlIHRyeSB0byBwcmVkaWN0IG91ciBvdXRjb21lIHZhcmlhYmxlLgoKRmlyc3QgbGV0J3MganVzdCBnZXQgYSBnZW5lcmFsIHNlbnNlIG9mIG91ciBkYXRhLiBXZSBjYW4gZG8gdGhhdCB1c2luZyB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSAoaXQgaXMgYWxzbyBpbiB0aGUgYHRpYmJsZWAgcGFja2FnZSkuCgpXZSB3aWxsIGFsc28gdXNlIHRoZSBgJT4lYCBwaXBlIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGRlZmluZSB0aGUgaW5wdXQgZm9yIGxhdGVyIHNlcXVlbnRpYWwgc3RlcHMuIFRoaXMgd2lsbCBtYWtlIG1vcmUgc2Vuc2Ugd2hlbiB3ZSBoYXZlIG11bHRpcGxlIHNlcXVlbnRpYWwgc3RlcHMgdXNpbmcgdGhlIHNhbWUgZGF0YSBvYmplY3QuIFRvIHVzZSB0aGUgcGlwZSBub3RhdGlvbiB3ZSBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgZHBseXIgYXMgd2VsbC4KCkZvciBleGFtcGxlIGhlcmUgd2Ugd2lsbCBmaXJzdCBncmFiIHRoZSBgcG1gIGRhdGEgb2JqZWN0LCB0aGVuIHdlIHVzZSB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb24gaXQgYmFzZWQgb24gdGhlIHBpcGUgbm90YXRpb24uCgoKYGBge3J9CnBtICU+JQogIGRwbHlyOjpnbGltcHNlKCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIDg3NiBtb25pdG9ycyBhbmQgdGhhdCB3ZSBoYXZlIDUwIHRvdGFsIHZhcmlhYmxlcyAtIG9uZSBvZiB3aGljaCBpcyB0aGUgb3V0Y29tZS4gSW4gdGhpcyBjYXNlIG91ciBvdXRjb21lIHZhcmlhYmxlIGlzIGNhbGxlZCBgdmFsdWVgLiAKCk5vdGljZSB0aGF0IHNvbWUgb2YgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIHdvdWxkIHRoaW5rIG9mIGFzIGZhY3RvcnMgKGNhdGVnb3JpY2FsKSBhcmUgY3VycmVudGx5IG9mIGNsYXNzIGRvdWJsZSBhcyBpbmRpY2F0ZWQgYnkgdGhlIGA8ZGJsPmAganVzdCB0byB0aGUgcmlnaHQgb2YgdGhlIGNvbHVtbiBuYW1lcy92YXJpYWJsZSBuYW1lcyBpbiB0aGUgYGdsaW1wc2UoKWAgb3V0cHV0LiBGb3IgZXhhbXBsZSB0aGUgbW9uaXRvciBJRCAoaWQpLCB0aGUgRmVkZXJhbCBJbmZvcm1hdGlvbiBQcm9jZXNzaW5nIFN0YW5kYXJkIG51bWJlciBmb3IgdGhlIGNvdW50eSB3aGVyZSB0aGUgbW9uaXRvciB3YXMgbG9jYXRlZCAoZmlwcyksIGFzIHdlbGwgYXMgdGhlIHpjdGEKCkxldCdzIGNvbnZlcnQgdGhlc2UgdmFyaWFibGVzIGludG8gZmFjdG9ycy4gV2UgY2FuIGRvIHRoaXMgdXNpbmcgdGhlIGBtdXRhdGVfYXQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSBhbmQgdGhlIGBhcy5mYWN0b3IoKWAgYmFzZSBmdW5jdGlvbi4gCgpJbiB0aGlzIGNhc2Ugd2UgYXJlIGFsc28gdXNpbmcgdGhlIG1hZ3JpdHRyIGFzc2lnbm1lbnQgcGlwZSBvciBkb3VibGUgcGlwZSB0aGF0IGxvb2tzIGxpa2UgdGhpcyBgJTw+JWAgb2YgdGhlIGBtYWdyaXR0cmAgcGFja2FnZS4gVGhpcyBhbGxvd3MgdXMgdXNlIHRoZSBgcG1gIGRhdGEgYXMgaW5wdXQgYnV0IGFsc28gcmVhc3NpZ24gdGhlIG91dHB1dCB0byB0aGUgc2FtZSBkYXRhIG9iamVjdCBuYW1lLgoKYGBge3J9CnBtICU8PiUKICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoaWQsIGZpcHMsIHpjdGEpLCBhcy5mYWN0b3IpIAoKZ2xpbXBzZShwbSkKYGBgCgpHcmVhdCEgTm93IHdlIGNhbiBzZWUgdGhhdCB0aGVzZSB2YXJpYWJsZXMgYXJlIG5vdyBmYWN0b3JzIGFzIGluZGljYXRlZCBieSBgPGZjdD5gIGFmdGVyIHRoZSB2YXJpYWJsZSBuYW1lLgoKVGhlIGBza2ltKClgIGZ1bmN0aW9uIG9mIHRoZSBgc2tpbXJgIHBhY2thZ2UgaXMgYWxzbyByZWFsbHkgaGVscGZ1bCBmb3IgZ2V0dGluZyBhIGdlbmVyYWwgc2Vuc2Ugb2YgeW91ciBkYXRhLgoKYGBge3J9CnNraW0ocG0pCmBgYAoKTm90aWNlIGhvdyB0aGVyZSBpcyBhIGNvbHVtbiBjYWxsZWQgYG5fbWlzc2luZ2AgYWJvdXQgdGhlIG51bWJlciBvZiB2YWx1ZXMgdGhhdCBhcmUgbWlzc2luZy4gSXQgbG9va3MgbGlrZSBvdXIgZGF0YSBpcyB2ZXJ5IGNvbXBsZXRlIGFuZCB3ZSBkbyBub3QgaGF2ZSBhbnkgbWlzc2luZyBkYXRhLiBUaGlzIGlzIGFsc28gaW5kaWNhdGVkIGJ5IHRoZSBgY29tcGxldGVfcmF0ZWAgdmFyaWFibGUsIHdoaWNoIHNob3dzIHRoZSByYXRpbyBvZiBjb21wbGV0ZW5lc3MsIGluIG91ciBjYXNlIGFsbCB2YXJpYWJsZXMgaGF2ZSBhIHZhbHVlIG9mIDEgaW5kaWNhdGluZyB0aGV5IGFyZSBmdWxseSBjb21wbGV0ZS4KClRoZSBgbl91bnFpdWVgIGNvbHVtbiBzaG93cyB1cyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSB2YWx1ZXMgZm9yIGVhY2ggb2Ygb3VyIGNvbHVtbnMuIFdlIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgNDkgc3RhdGVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhLCBhbmQgd2Uga25vdyB0aGF0IHRoZSBkYXRhIHNob3VsZCBiZSBvZiB0aGUgY29udGlndW91cyBzdGF0ZXMuIExldCdzIHRha2UgYSBsb29rIHRvIHNlZSB3aGljaCBzdGF0ZXMgYXJlIGluY2x1ZGVkOgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpwbSAlPiUgCiAgZGlzdGluY3Qoc3RhdGUpICU+JQogIHByaW50KG4gPSAxZTMpCmBgYAojIyMjCgpMb29rcyBsaWtlICJEaXN0cmljdCBvZiBDb2x1bWJpYSIgaXMgYmVpbmcgaW5jbHVkZWQgYXMgYSBzdGF0ZS4gV2UgY2FuIHNlZSB0aGF0IGluZGVlZCBBbGFza2EgYW5kIEhhd2FpaSBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBkYXRhLgoKSGVyZSBpcyBhbm90aGVyIG1ldGhvZCBvZiBsb29raW5nIGF0IHRoZSBkYXRhIHVzaW5nIHRoZSBgZGZTdW1tYXJ5KClgIGZ1bmN0aW9uIG9mIHRoZSBgc3VtbWFyeXRvb2xzYHBhY2thZ2UuIFdlIG5lZWQgdG8gY29weSBhbmQgcGFzdGUgdGhlIG91dHB1dCBpbnRvIHRoZSBybWFya2Rvd24uCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkZlN1bW1hcnkocG0sIHBsYWluLmFzY2lpID0gRkFMU0UsIHN0eWxlID0gImdyaWQiLCAKICAgICAgICAgIGdyYXBoLm1hZ25pZiA9IDAuNDUsICB0bXAuaW1nLmRpciA9ICJ0bXAiKQpgYGAKCioqRGltZW5zaW9uczoqKiA4NzYgeCA1MCAgCioqRHVwbGljYXRlczoqKiAwICAKCistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgTm8gfCBWYXJpYWJsZSAgICAgICAgICAgICAgICAgICAgIHwgU3RhdHMgLyBWYWx1ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICB8IEZyZXFzICglIG9mIFZhbGlkKSAgfCBHcmFwaCAgICAgICAgICAgICAgIHwgVmFsaWQgIHwgTWlzc2luZyB8Cis9PT09Kz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0rPT09PT09PT09PT09PT09PT09PT09Kz09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PSs9PT09PT09PT0rCnwgMSAgfCBpZFwgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMDMuMDAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDEwMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDEwMjcuMDAwMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEwMzMuMTAwMlwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDEwNDkuMTAwM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDEwNTUuMDAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDEwNjkuMDAwM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDEwNzMuMDAyM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDEwNzMuMTAwNVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDEwNzMuMTAwOVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAxMDczLjEwMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA4NjYgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg2NiAoOTguOSUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMiAgfCB2YWx1ZVwgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuOCAoMi42KVwgICAgICAgICAgICAgICAgICB8IDg3NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMyA8IDExLjIgPCAyMy4yXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjEgKDAuMikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMyAgfCBmaXBzXCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMDNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDEwMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDEwMjdcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEwMzNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDEwNDlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDEwNTVcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDEwNjlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDEwNzNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDggKCAwLjklKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDEwODlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDEwOTdcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAxMTAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA1NTkgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg1OCAoOTguMCUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNCAgfCBsYXRcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzguNSAoNC42KVwgICAgICAgICAgICAgICAgICB8IDg3NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMjUuNSA8IDM5LjMgPCA0OC40XCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2LjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNSAgfCBsb25cICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogLTkxLjcgKDE1KVwgICAgICAgICAgICAgICAgICB8IDg3NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLTEyNC4yIDwgLTg3LjUgPCAtNjhcICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOC41ICgtMC4yKSAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNiAgfCBzdGF0ZVwgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIENhbGlmb3JuaWFcICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg1ICggOS43JSlcICAgICAgICAgfCAhW10odG1wL2RzMDEwNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIE9oaW9cICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDQ0ICggNS4wJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIElsbGlub2lzXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDM4ICggNC4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIEluZGlhbmFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDM2ICggNC4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIE5vcnRoIENhcm9saW5hXCAgICAgICAgICAgICAgICAgICAgICB8IDM1ICggNC4wJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIFBlbm5zeWx2YW5pYVwgICAgICAgICAgICAgICAgICAgICAgICB8IDMyICggMy43JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIE1pY2hpZ2FuXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMwICggMy40JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIEZsb3JpZGFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI5ICggMy4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIEdlb3JnaWFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI4ICggMy4yJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBUZXhhc1wgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI3ICggMy4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyAzOSBvdGhlcnMgXSAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDQ5MiAoNTYuMiUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNyAgfCBjb3VudHlcICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIEplZmZlcnNvblwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDE4ICggMi4xJSlcICAgICAgICAgfCAhW10odG1wL2RzMDEwNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIENvb2tcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEyICggMS40JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIEhhbWlsdG9uXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDExICggMS4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIExha2VcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDExICggMS4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIExvcyBBbmdlbGVzXCAgICAgICAgICAgICAgICAgICAgICAgICB8IDEwICggMS4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIFdheW5lXCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEwICggMS4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIFdhc2hpbmd0b25cICAgICAgICAgICAgICAgICAgICAgICAgICB8IDkgKCAxLjAlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIEN1eWFob2dhXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIEphY2tzb25cICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBNYWRpc29uXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA0NjEgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDc3NCAoODguNCUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgOCAgfCBjaXR5XCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIE5vdCBpbiBhIGNpdHlcICAgICAgICAgICAgICAgICAgICAgICB8IDEwMyAoMTEuOCUpXCAgICAgICAgfCAhW10odG1wL2RzMDEwOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIE5ldyBZb3JrXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDkgKCAxLjAlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIENsZXZlbGFuZFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgKCAwLjclKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIEJhbHRpbW9yZVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIENoaWNhZ29cICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIERldHJvaXRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIE1pbHdhdWtlZVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIE5ldyBIYXZlblwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIFBoaWxhZGVscGhpYVwgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBTcHJpbmdmaWVsZFwgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA1OTcgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcyMyAoODIuNSUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgOSAgfCBDTUFRXCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogOC40ICgzKVwgICAgICAgICAgICAgICAgICAgICB8IDYwMSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMS42IDwgOC42IDwgMjMuMVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjcgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTAgfCB6Y3RhXCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMjJcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDExMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDExMDNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEyMDFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDE2MDhcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDE4MzJcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDE4NDBcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDE4NjNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDE5MDRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDIxMTNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAyMTE5XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA4MzIgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg2NCAoOTguNiUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTEgfCB6Y3RhX2FyZWFcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTgzMTczNDgxLjkgKDU0MjU5ODg3OC41KVwgICB8IDg0MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTU0NTkgPCAzNzY1MzU2MC41IDwgODE2NDgyMDYyNVwgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNDU4MzY5MDYuNSAoMykgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTIgfCB6Y3RhX3BvcFwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQyMjcuNiAoMTc3NzIuMilcICAgICAgICAgICB8IDgzNyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDIyMDE0IDwgOTUzOTdcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyNTIwNy44ICgwLjcpICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTMgfCBpbXBfYTUwMFwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQuNyAoMTkuMylcICAgICAgICAgICAgICAgICB8IDgxNiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDI1LjEgPCA2OS42XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzNi41ICgwLjgpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTQgfCBpbXBfYTEwMDBcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQuMyAoMTgpXCAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDI0LjUgPCA2Ny41XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzMy4zICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTUgfCBpbXBfYTUwMDBcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTkuOSAoMTQuNylcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgMTkuMSA8IDc0LjZcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyMy4zICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTYgfCBpbXBfYTEwMDAwXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTUuOCAoMTMuOClcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgMTIuNCA8IDcyLjFcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOS42ICgwLjkpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTcgfCBpbXBfYTE1MDAwXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTMuNCAoMTMuMSlcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgOS43IDwgNzEuMVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNy4zICgxKSAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTggfCBjb3VudHlfYXJlYVwgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzc2ODcwMTk5Mi4xICg2MjEyODI5NTUzLjYpXCB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMzM3MDM1MTIgPCAxNjkwODI2NTY2LjUgPCA1MTk0NzIyOTUwOVwgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNzYxNjU1OTExLjUgKDEuNikgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTkgfCBjb3VudHlfcG9wXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNjg3Mjk4LjQgKDEyOTM0ODguNylcICAgICAgICB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNzgzIDwgMjgwNzMwLjUgPCA5ODE4NjA1XCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2NDIyMTEgKDEuOSkgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjAgfCBsb2dfZGlzdF90b19wcmlzZWNcICAgICAgICAgIHwgTWVhbiAoc2QpIDogNi4yICgxLjQpXCAgICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLTEuNSA8IDYuNCA8IDEwLjVcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjcgKDAuMikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjEgfCBsb2dfcHJpX2xlbmd0aF81MDAwXCAgICAgICAgIHwgTWVhbiAoc2QpIDogOS44ICgxLjEpXCAgICAgICAgICAgICAgICAgICB8IDU4NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOC41IDwgMTAuMSA8IDEyXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjIgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjIgfCBsb2dfcHJpX2xlbmd0aF8xMDAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuOSAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDY4NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS4yIDwgMTEuMiA8IDEzXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjMgfCBsb2dfcHJpX2xlbmd0aF8xNTAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTEuNSAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDcyNiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS42IDwgMTEuNyA8IDEzLjZcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjUgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjQgfCBsb2dfcHJpX2xlbmd0aF8yNTAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTIuMiAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDc4NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTAuMSA8IDEyLjUgPCAxNC40XCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjQgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjUgfCBsb2dfcHJpc2VjX2xlbmd0aF81MDBcICAgICAgIHwgTWVhbiAoc2QpIDogNyAoMSlcICAgICAgICAgICAgICAgICAgICAgICB8IDM4MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNi4yIDwgNi4yIDwgOS40XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjYgfCBsb2dfcHJpc2VjX2xlbmd0aF8xMDAwXCAgICAgIHwgTWVhbiAoc2QpIDogOC42ICgwLjgpXCAgICAgICAgICAgICAgICAgICB8IDU5MSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNy42IDwgOC43IDwgMTAuNVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjcgfCBsb2dfcHJpc2VjX2xlbmd0aF81MDAwXCAgICAgIHwgTWVhbiAoc2QpIDogMTEuMyAoMC44KVwgICAgICAgICAgICAgICAgICB8IDg1MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOC41IDwgMTEuNCA8IDEyLjhcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAwLjkgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjggfCBsb2dfcHJpc2VjX2xlbmd0aF8xMDAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTIuNCAoMC43KVwgICAgICAgICAgICAgICAgICB8IDg2NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS4yIDwgMTIuNSA8IDEzLjhcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjkgfCBsb2dfcHJpc2VjX2xlbmd0aF8xNTAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTMgKDAuNylcICAgICAgICAgICAgICAgICAgICB8IDg2OSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS42IDwgMTMuMSA8IDE0LjRcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzAgfCBsb2dfcHJpc2VjX2xlbmd0aF8yNTAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTMuOCAoMC43KVwgICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTAuMSA8IDEzLjkgPCAxNS4yXCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzEgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTAwMDBcIHwgTWVhbiAoc2QpIDogNCAoMi40KVwgICAgICAgICAgICAgICAgICAgICB8IDgyOCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQuMyA8IDkuMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjUgKDAuNikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzIgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTUwMDBcIHwgTWVhbiAoc2QpIDogNC43ICgyLjIpXCAgICAgICAgICAgICAgICAgICB8IDg1NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUgPCA5LjRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjkgKDAuNSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzMgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMjUwMDBcIHwgTWVhbiAoc2QpIDogNS43ICgyLjEpXCAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuOSA8IDkuN1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjYgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzQgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTAwMDBcIHwgTWVhbiAoc2QpIDogNC4zICgyLjMpXCAgICAgICAgICAgICAgICAgICB8IDgyOSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQuNiA8IDkuM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjQgKDAuNSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzUgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTUwMDBcIHwgTWVhbiAoc2QpIDogNS4xICgyLjIpXCAgICAgICAgICAgICAgICAgICB8IDg1NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuNCA8IDkuN1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjggKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzYgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMjUwMDBcIHwgTWVhbiAoc2QpIDogNi4xICgyKVwgICAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYuNCA8IDkuOVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjQgKDAuMykgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzcgfCBwb3BkZW5zX2NvdW50eVwgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNTUxLjggKDE3MTEuNSlcICAgICAgICAgICAgICB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4zIDwgMTU2LjcgPCAyNjgyMS45XCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA0NzAgKDMuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzggfCBwb3BkZW5zX3pjdGFcICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTI3OS43ICgyNzU3LjUpXCAgICAgICAgICAgICB8IDg0MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYxMC4zIDwgMzA0MTguOFwgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMjgxLjQgKDIuMikgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzkgfCBub2hzXCAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNyAoNy4yKVwgICAgICAgICAgICAgICAgICAgICB8IDIxNSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuMSA8IDEwMFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2LjEgKDEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDAgfCBzb21laHNcICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuMiAoNi4yKVwgICAgICAgICAgICAgICAgICB8IDIzMCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0MC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDkuNCA8IDcyLjJcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA4ICgwLjYpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDEgfCBoc1wgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzAuMyAoMTEuNClcICAgICAgICAgICAgICAgICB8IDM0NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0MS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDMwLjggPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMi4zICgwLjQpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDIgfCBzb21lY29sbGVnZVwgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjEuNiAoOC42KVwgICAgICAgICAgICAgICAgICB8IDI0MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Mi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDIxLjMgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA3LjIgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDMgfCBhc3NvY2lhdGVcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNy4xICg0KVwgICAgICAgICAgICAgICAgICAgICB8IDE1NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0My5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDcuMSA8IDcxLjRcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjkgKDAuNikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDQgfCBiYWNoZWxvclwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTQuOSAoOS43KVwgICAgICAgICAgICAgICAgICB8IDMwMSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0NC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDEyLjkgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMC40ICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDUgfCBncmFkXCAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogOC45ICg4LjYpXCAgICAgICAgICAgICAgICAgICB8IDI0NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0NS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYuNyA8IDEwMFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA3LjEgKDEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDYgfCBwb3ZcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTUgKDExLjMpXCAgICAgICAgICAgICAgICAgICB8IDM0NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Ni5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDEyLjEgPCA2NS45XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNC43ICgwLjgpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDcgfCBoc19vcmxlc3NcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNDcuNSAoMTYuOClcICAgICAgICAgICAgICAgICB8IDQ2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Ny5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQ4LjcgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyMS4yICgwLjQpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDggfCB1cmMyMDEzXCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMi45ICgxLjUpXCAgICAgICAgICAgICAgICAgICB8IDEgOiAyMDMgKDIzLjIlKVwgICAgfCAhW10odG1wL2RzMDE0OC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8IDIgOiAxNjMgKDE4LjYlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMSA8IDMgPCA2XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMgOiAyMjggKDI2LjAlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjUpICAgICAgICAgICAgICAgICAgICAgICB8IDQgOiAxMjMgKDE0LjAlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgOiAxMDEgKDExLjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgOiAgNTggKCA2LjYlKSAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDkgfCB1cmMyMDA2XCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMyAoMS41KVwgICAgICAgICAgICAgICAgICAgICB8IDEgOiAxOTUgKDIyLjMlKVwgICAgfCAhW10odG1wL2RzMDE0OS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8IDIgOiAxNjIgKDE4LjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMSA8IDMgPCA2XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMgOiAyMjEgKDI1LjIlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjUpICAgICAgICAgICAgICAgICAgICAgICB8IDQgOiAxMjcgKDE0LjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgOiAxMTUgKDEzLjElKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgOiAgNTYgKCA2LjQlKSAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNTAgfCBhb2RcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNDMuNyAoMTkuNilcICAgICAgICAgICAgICAgICB8IDU4MSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE1MC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNSA8IDQwLjIgPCAxNDNcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOCAoMC40KSAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCgoKV2UgY2FuIHNlZSB0aGF0IGZvciBtYW55IHZhcmlhYmxlcyB0aGVyZSBhcmUgbWFueSBsb3cgdmFsdWVzIGFzIHRoZSBkaXN0cmlidXRpb24gc2hvd3MgdHdvIHBlYWtzLCBvbmUgbmVhciB6ZXJvIGFuZCBhbm90aGVyIHdpdGggYSBoaWdoZXIgdmFsdWUuIFRoaXMgaXMgdHJ1ZSBmb3IgdGhlIGltcCB2YXJpYWJsZXMgKG1lYXN1cmVzIG9mIGRldmVsb3BtZW50KSwgdGhlIG5laSB2YXJpYWJsZXMgKG1lYXN1cmVzIG9mIGVtaXNzaW9uIHNvdXJjZXMpIGFuZCB0aGUgcm9hZCBkZW5zaXR5IHZhcmlhYmxlcy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIHJhbmdlIG9mIHNvbWUgb2YgdGhlIHZhcmlhYmxlcyBpcyB2ZXJ5IGxhcmdlLCBpbiBwYXJ0aWN1bGFyIHRoZSBhcmVhIGFuZCBwb3B1bGF0aW9uIHJlbGF0ZWQgdmFyaWFibGVzLgoKCkluIHByZWRpY3Rpb24gYW5hbHlzZXMsIGl0IGlzIGFsc28gdXNlZnVsIHRvIGV2YWx1YXRlIGlmIGFueSBvZiB0aGUgdmFyaWFibGVzIGFyZSBjb3JyZWxhdGVkLgoKSW50dWl0aXZlbHkgd2UgY2FuIGV4cGVjdCBzb21lIG9mIG91ciB2YXJpYWJsZXMgdG8gYmUgY29ycmVsYXRlZC4KCldlIGV4cGVjdCB0aGUgZGV2ZWxvcG1lbnQgdmFyaWFibGVzIChpbXApIHRvIGJlIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLCB3ZSBleHBlY3QgdGhlIHJvYWQgZGVuc2l0eSB2YXJpYWJsZXMgdG8gYmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIsIHdlIGV4cGVjdCB0aGUgZW1pc3Npb24gdmFyaWFibGVzIHRvIGJlIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLCBhbmQgd2UgYWxzbyBleHBlY3QgdGhlc2UgdmFyaWFibGVzIHRvIGJlIGNvcnJlbGF0ZWQgd2l0aCBvbmUgYW5vdGhlciBhbmQgbGlrZWx5IGNvcnJlbGF0ZWQgd2l0aCBwb3B1bGF0aW9uIGRlbnNpdHkuIFdlIGNhbiBnZXQgYSBuaWNlIHZpc3VhbGl6YXRpb24gb2YgY29ycmVsYXRpb24gdXNpbmcgdGhlIGBnZ2NvcnIoKWAgZnVuY3Rpb24gYW5kIHRoZSBgZ2dwYWlycygpYCBmdW5jdGlvbiBvZiB0aGUgYEdHYWxseWAgcGFja2FnZS4gdG8gc2VsZWN0IG91ciB2YXJpYWJsZXMgb2YgaW50ZXJlc3Qgd2UgY2FuIHVzZSB0aGUgYHNlbGVjdCgpYCBmdW5jdGlvbiB3aXRoIHRoZSBgY29udGFpbnMoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZS4gCgpGaXJzdCBsZXQncyBsb29rIGF0IHRoZSBpbXAvZGV2ZWxvcG1lbnQgdmFyaWFibGVzLiAKYGBge3IsIG91dC53aWR0aCA9ICI0MDBweCJ9CnNlbGVjdChwbSwgY29udGFpbnMoImltcCIpKSAlPiUKICBnZ2NvcnIocGFsZXR0ZSA9ICJSZEJ1IiwgbGFiZWwgPSBUUlVFKQoKc2VsZWN0KHBtLCBjb250YWlucygiaW1wIikpICU+JQogIGdncGFpcnMoKQogIApgYGAKCkluZGVlZCwgd2UgY2FuIHNlZSB0aGF0IGltcF9hMTAwMCBhbmQgaW1wX2E1MDAgYXJlIHBlcmZlY3RseSBjb3JyZWxhdGVkLCBhcyB3ZWxsIGFzIGltcF9hMTAwMDAsIGltcF9hMTUwMDAuCgoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSByb2FkIGRlbnNpdHkgZGF0YToKCmBgYHtyLCBmaWcud2VpZ2h0PTEyfQpzZWxlY3QocG0sIGNvbnRhaW5zKCJwcmkiKSkgJT4lCiAgZ2djb3JyKHBhbGV0dGUgPSAiUmRCdSIsICBoanVzdCA9IC44NSwgc2l6ZSA9IDMsCiAgICAgICBsYXlvdXQuZXhwPTIsIGxhYmVsID0gVFJVRSkKCnNlbGVjdChwbSwgY29udGFpbnMoInByaSIpKSAlPiUKICBnZ3BhaXJzKCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgd2hpbGUgc29tZSBvZiB0aGUgcm9hZCBkZW5zaXR5IHZhcmlhYmxlcyBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBvbmUgYW5vdGhlciAob3IgYW50aS1jb3JyZWxhdGVkKSwgdGhlcmUgYXJyIHNvbWUgdmFyaWFibGVzIHRoYXQgYXJlIGxlc3MgY29ycmVsYXRlZCB3aXRoIG9uZSBhbm90aGVyLgoKRmluYWxseSBsZXQncyBsb29rIGF0IHRoZSBlbWlzc2lvbiB2YXJpYWJsZXMuCgpgYGB7cn0Kc2VsZWN0KHBtLCBjb250YWlucygibmVpIikpICU+JQogIGdnY29ycihwYWxldHRlID0gIlJkQnUiLCAgaGp1c3QgPSAuODUsIHNpemUgPSAzLAogICAgICAgbGF5b3V0LmV4cD0yLCBsYWJlbCA9IFRSVUUpCgpzZWxlY3QocG0sIGNvbnRhaW5zKCJuZWkiKSkgJT4lCiAgZ2dwYWlycygpCmBgYAoKV2Ugd291bGQgYWxzbyBleHBlY3QgdGhlIHBvcHVsYXRpb24gZGVuc2l0eSBkYXRhIG1pZ2h0IGNvcnJlbGF0ZSB3aXRoIHNvbWUgb2YgdGhlc2UgdmFyaWFibGVzLiBMZXQncyB0YWtlIGEgbG9vay4KCmBgYHtyfQpwbSAlPiUKc2VsZWN0KGxvZ19uZWlfMjAwOF9wbTI1X3N1bV8xMDAwMCwgcG9wZGVuc19jb3VudHksIGxvZ19wcmlfbGVuZ3RoXzEwMDAwLCBpbXBfYTEwMDAwKSAlPiUKICBnZ2NvcnIocGFsZXR0ZSA9ICJSZEJ1IiwgIGhqdXN0ID0gLjg1LCBzaXplID0gMywKICAgICAgIGxheW91dC5leHA9MiwgbGFiZWwgPSBUUlVFKQoKcG0gJT4lCnNlbGVjdChsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTAwMDAsIHBvcGRlbnNfY291bnR5LCBsb2dfcHJpX2xlbmd0aF8xMDAwMCwgaW1wX2ExMDAwMCwgY291bnR5X3BvcCkgJT4lCiAgZ2dwYWlycygpCmBgYAoKCkludGVyZXN0aW5nLCBzbyB0aGVzZSB2YXJpYWJsZXMgZG9uJ3QgYXBwZWFyIHRvIGJlIGhpZ2hseSBjb3JyZWxhdGVkLCB0aGVyZWZvcmUgd2UgbWlnaHQgbmVlZCB2YXJpYWJsZXMgZnJvbSBlYWNoIG9mIHRoZSBjYXRlZ29yaWVzIHRvIHByZWRpY3Qgb3VyIG1vbml0b3IgUE1+Mi41fiBwb2xsdXRpb24gdmFsdWVzLgoKV2Ugc2VlbSB0byBoYXZlIHNvbWUgcHJldHR5IGV4dHJlbWUgcG9wdWxhdGlvbiB2YWx1ZXMgdGhvdWdoLCBzbyBsZXQncyBzZWUgd2hhdCBoYXBwZW5zIHdoZW4gd2UgdGFrZSB0aGUgbG9nIHZhbHVlLgoKYGBge3J9CnBtICU+JQogIG11dGF0ZShsb2dfcG9wZGVuc19jb3VudHk9IGxvZyhwb3BkZW5zX2NvdW50eSkpICU+JQpzZWxlY3QobG9nX25laV8yMDA4X3BtMjVfc3VtXzEwMDAwLCBsb2dfcG9wZGVuc19jb3VudHksIGxvZ19wcmlfbGVuZ3RoXzEwMDAwLCBpbXBfYTEwMDAwKSAlPiUKICBnZ2NvcnIocGFsZXR0ZSA9ICJSZEJ1IiwgIGhqdXN0ID0gLjg1LCBzaXplID0gMywKICAgICAgIGxheW91dC5leHA9MiwgbGFiZWwgPSBUUlVFKQoKcG0gJT4lCiAgbXV0YXRlKGxvZ19wb3BkZW5zX2NvdW50eT0gbG9nKHBvcGRlbnNfY291bnR5KSkgJT4lCiAgbXV0YXRlKGxvZ19wb3BfY291bnR5ID0gbG9nKGNvdW50eV9wb3ApKSAlPiUKc2VsZWN0KGxvZ19uZWlfMjAwOF9wbTI1X3N1bV8xMDAwMCwgbG9nX3BvcGRlbnNfY291bnR5LCBsb2dfcHJpX2xlbmd0aF8xMDAwMCwgaW1wX2ExMDAwMCwgbG9nX3BvcF9jb3VudHkpICU+JQogIGdncGFpcnMoKQpgYGAKCkluZGVlZCB0aGlzIGluY3JlYXNlZCB0aGUgY29ycmVsYXRpb24sIGJ1dCB2YXJpYWJsZXMgZnJvbSBlYWNoIG9mIHRoZXNlIGNhdGVnb3JpZXMgbWF5IHN0aWxsIHByb3ZlIHRvIGJlIHVzZWZ1bCBmb3IgcHJlZGljdGlvbi4KCgojIyBEYXRhIEFuYWx5c2lzCgpOb3cgdGhhdCB3ZSBoYXZlIGEgc2Vuc2Ugb2Ygd2hhdCBvdXIgZGF0YSBpcyBsaWtlIHdlIGNhbiBnZXQgc3RhcnRlZCB3aXRoIGRhdGEgYW5hbHlzaXMuCgoKIyMjIFRoZSB0aWR5bW9kZWxzIGVjb3N5c3RlbQoKVG8gcGVyZm9ybSBvdXIgYW5hbHlzaXMgd2Ugd2lsbCBiZSB1c2luZyB0aGUgYHRpZHltb2RlbHNgIHN1aXRlIG9mIHBhY2thZ2VzLiBZb3UgbWF5IGJlIGZhbWlsaWFyIHdpdGggdGhlIG9sZGVyIHBhY2thZ2VzIGBjYXJldGAgb3IgYG1scmAgd2hpY2ggYXJlIGFsc28gZm9yIG1hY2hpbmUgbGVhcm5pbmcgYW5kIG1vZGVsaW5nIGJ1dCBhcmUgbm90IGEgcGFydCBvZiB0aGUgYHRpZHl2ZXJzZWAuIFtNYXggS3Vobl0oaHR0cHM6Ly9yZXNvdXJjZXMucnN0dWRpby5jb20vYXV0aG9ycy9tYXgta3Vobil7dGFyZ2V0PSJfYmxhbmsifSBkZXNjcmliZXMgYHRpZHltb2RlbHNgIGxpa2UgdGhpczoKCj4gIk90aGVyIHBhY2thZ2VzLCBzdWNoIGFzIGNhcmV0IGFuZCBtbHIsIGhlbHAgdG8gc29sdmUgdGhlIFIgbW9kZWwgQVBJIGlzc3VlLiBUaGVzZSBwYWNrYWdlcyBkbyBhIGxvdCBvZiBvdGhlciB0aGluZ3MgdG9vOiBwcmVwcm9jZXNzaW5nLCBtb2RlbCB0dW5pbmcsIHJlc2FtcGxpbmcsIGZlYXR1cmUgc2VsZWN0aW9uLCBlbnNlbWJsaW5nLCBhbmQgc28gb24uIEluIHRoZSB0aWR5dmVyc2UsIHdlIHN0cml2ZSB0byBtYWtlIG91ciBwYWNrYWdlcyBtb2R1bGFyIGFuZCBwYXJzbmlwIGlzIGRlc2lnbmVkIG9ubHkgdG8gc29sdmUgdGhlIGludGVyZmFjZSBpc3N1ZS4gSXQgaXMgbm90IGRlc2lnbmVkIHRvIGJlIGEgZHJvcC1pbiByZXBsYWNlbWVudCBmb3IgY2FyZXQuClRoZSB0aWR5bW9kZWxzIHBhY2thZ2UgY29sbGVjdGlvbiwgd2hpY2ggaW5jbHVkZXMgcGFyc25pcCwgaGFzIG90aGVyIHBhY2thZ2VzIGZvciBtYW55IG9mIHRoZXNlIHRhc2tzLCBhbmQgdGhleSBhcmUgZGVzaWduZWQgdG8gd29yayB0b2dldGhlci4gV2UgYXJlIHdvcmtpbmcgdG93YXJkcyBoaWdoZXItbGV2ZWwgQVBJcyB0aGF0IGNhbiByZXBsaWNhdGUgYW5kIGV4dGVuZCB3aGF0IHRoZSBjdXJyZW50IG1vZGVsIHBhY2thZ2VzIGNhbiBkby4iCgoKIyMjIFRoZSBtYWpvciBiZW5lZml0cyBvZiB0aWR5bW9kZWxzCjEpIHN0YW5kYXJkaXplZCB3b3JrZmxvdy9mb3JtYXQvbm90YXRpb24gYWNyb3NzIGRpZmZlcmVudCB0eXBlcyBvZiBhbGdvcml0aG1zCjIpIGNhbiBlYXNpbHkgbW9kaWZ5IHByZXByb2Nlc3NpbmcsIGFsZ29yaXRobSBjaG9pY2UsIGFuZCBoeXBlci1wYXJhbWV0ZXIgdHVuaW5nIG1ha2luZyBvcHRpbWl6YXRpb24gZWFzeQoKCiMjIyBUaGUgbWFjaGluZSBsZWFybmluZyBwcm9jZXNzCgoKIyMjIFRoZSB0aWR5bW9kZWxzIGVjb3N5c3RlbSAtIGFuIG92ZXJ2aWV3CgpUaGVyZSBhcmUgbWFueSBwYWNrYWdlcyBpbiB0aGUgdGlkeW1vZGVscyBlY29zeXN0ZW0gd2hpY2ggYXNzaXN0IHdpdGggdGhlIHZhcmlvdXMgc3RlcHMgb2YgdGhlIG1hY2hpbmUgbGVhcm5pbmcgcHJvY2VzczoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwic2ltcGxldGlkeW1vZGVscy5wbmciKSkKYGBgCgoKVGhpcyBpcyB0aGUgb3ZlcmFsbCBwcm9jZXNzOgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJNYWNoaW5lTGVhcm5pbmcucG5nIikpCmBgYAoKVGhlcmUgYXJlIHR3byBkaXN0aW5jdCBnb2FscyBvZiBzdXBlcnZpc2VkIG1hY2hpbmUgbGVhcm5pbmc6ICAKCjEpIFByZWRpY3Rpb24gIAoyKSBDbGFzc2lmaWNhdGlvbiAgCgpXZSB3aWxsIGJlIHBlcmZvcm1pbmcgYSBwcmVkaWN0aW9uIGFuYWx5c2lzICh3aGljaCBpcyBhbHNvIHJlZmVyZWQgdG8gYXMgcmVncmVzc2lvbiksIHdoaWNoIGFpbXMgdG8gcHJlZGljdCAqKmNvbnRpbnVvdXMgb3V0Y29tZSoqIHZhcmlhYmxlcyBnaXZlbiBhIG51bWJlciBvZiBwcmVkaWN0b3JzL2V4cGxhbmF0b3J5IHZhcmlhYmxlcy9mZWF0dXJlcy9wYXJhbWV0ZXJzLCBhcyB3ZSBoYXZlIGFscmVhZHkgZGVzY3JpYmVkLgoKQ2xhc3NpZmljYXRpb24gb24gdGhlIG90aGVyIGhhbmQgYWltcyB0byBkaXNjZXJuIG9yIHByZWRpY3QgZ3JvdXAgaWRlbnRpdHkgZm9yIGEgKipjYXRlZ29yaWNhbCBvdXRjb21lKiogYmFzZWQgb24gYSBudW1iZXIgb2YgcHJlZGljdG9ycy9leHBsYW5hdG9yeSB2YXJpYWJsZXMvZmVhdHVyZXMvcGFyYW1ldGVycy4KClRoZSBvdmVyYWxsIHByb2Nlc3MgaXMgdGhlIHNhbWUgaW4gZWl0aGVyIGNhc2UuIAoKIyMjIFNwbGl0dGluZyB0aGUgRGF0YQoKVGhlIGZpcnN0IHN0ZXAgYWZ0ZXIgZGF0YSBleHBsb3JhdGlvbiBpbiBtYWNoaW5lIGxlYXJuaW5nIGFuYWx5c2lzIGlzIHRvIFtzcGxpdCB0aGUgZGF0YV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3RyYWluLXZhbGlkYXRpb24tYW5kLXRlc3Qtc2V0cy03MmNiNDBjYmE5ZTcpe3RhcmdldD0iX2JsYW5rIn0gaW50byAqKnRyYWluaW5nKiogYW5kICoqdGVzdGluZyoqIGRhdGFzZXRzLiAKClRoZSB0cmFpbmluZyBkYXRhc2V0IHdpbGwgYmUgdXNlZCB0byBidWlsZCBhbmQgdHVuZSBvdXIgbW9kZWwuIFRoaXMgaXMgdGhlIGRhdGEgdGhhdCB0aGUgbW9kZWwgImxlYXJucyIgb24uCgpUaGUgdGVzdGluZyBzZXQgd2lsbCBiZSB1c2VkIHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwgaW4gYSBtb3JlIGdlbmVyYWxpemFibGUgd2F5LiBXaGF0IGRvIHdlIG1lYW4gYnkgImdlbmVyYWxpemFibGUiPwoKUmVtZW1iZXIgdGhhdCBvdXIgbWFpbiBnb2FsIGlzIHRvIHVzZSBvdXIgbW9kZWwgdG8gYmUgYWJsZSB0byBwcmVkaWN0IGFpciBwb2xsdXRpb24gbGV2ZWxzIGluIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBubyBncmF2aW1ldHJpYyBtb25pdG9ycy4gVGhlcmVmb3JlLCBpZiBvdXIgbW9kZWwgaXMgc3VwZXIgZ29vZCBhdCBwcmVkaWN0aW5nIGFpciBwb2xsdXRpb24gd2l0aCB0aGUgZGF0YSB0aGF0IHdlIHVzZSB0byBidWlsZCBpdCwgaXQgbWlnaHQgbm90IGRvIHRoZSBiZXN0IGpvYiBmb3IgdGhlIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBmZXcgdG8gbm8gbW9uaXRvcnMuIFRoaXMgd291bGQgY2F1c2UgdXMgdG8gaGF2ZSByZWFsbHkgZ29vZCBwcmVkaWN0aW9uIGFjY3VyYWN5IGFuZCB3ZSBtaWdodCBhc3N1bWUgdGhhdCB3ZSB3ZXJlIGdvaW5nIHRvIGRvIGEgZ29vZCBqb2IgZXN0aW1hdGluZyBhaXIgcG9sbHV0aW9uIGFueSB0aW1lIHdlIHVzZSBvdXIgbW9kZWwsIGJ1dCBpbiBmYWN0IHRoaXMgd291bGQgbGlrZWx5IG5vdCBiZSB0aGUgY2FzZS4gVGhpcyBzaXR1YXRpb24gaXMgd2hhdCB3ZSBjYWxsICoqW292ZXJmaXR0aW5nXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vdHJhaW4tdGVzdC1zcGxpdC1hbmQtY3Jvc3MtdmFsaWRhdGlvbi1pbi1weXRob24tODBiNjFiZWNhNGI2KXt0YXJnZXQ9Il9ibGFuayJ9ICoqLgoKT3ZlcmZpdHRpbmcgaGFwcGVucyB3aGVuIHdlIGVuZCB1cCBtb2RlbGluZyBub3Qgb25seSB0aGUgbWFqb3IgcmVsYXRpb25zaGlwcyBpbiBvdXIgZGF0YSBidXQgYWxzbyB0aGUgbm9pc2Ugd2l0aGluIG91ciBkYXRhLiAKCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vbWlyby5tZWRpdW0uY29tL21heC8xMTEwLzEqdEJFclhZVnZUdzJqU1VZSzd0aFUyQS5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXShodHRwczovL21pcm8ubWVkaXVtLmNvbS9tYXgvMTExMC8xKnRCRXJYWVZ2VHcyalNVWUs3dGhVMkEucG5nKV0KCklmIHdlIGdldCBmYWlybHkgZ29vZCBwcmVkaWN0aW9uIHdpdGggb3VyIHRlc3Rpbmcgc2V0IHRoZW4gd2Ugd2lsbCBrbm93IHRoYXQgb3VyIG1vZGVsIGNhbiBiZSBhcHBsaWVkIHRvIG90aGVyIGRhdGEgYW5kIHdpbGwgcGVyZm9ybSBmYWlybHkgd2VsbC4gV2Ugd2lsbCBkaXNjdXNzIHRoaXMgbW9yZSBsYXRlci4KCldlIHdpbGwgbm90IHRvdWNoIHRoZSB0ZXN0aW5nIHNldCB1bnRpbCB3ZSBoYXZlIGNvbXBsZXRlZCBvcHRpbWl6aW5nIG91ciBtb2RlbCB3aXRoIHRoZSB0cmFpbmluZyBzZXQuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBoYXZlIGEgbGVzcyBiaWFzZWQgZXZhbHVhdGlvbiBvZiBob3cgd2VsbCBvdXIgbW9kZWwgY2FuIGRvIHdpdGggb3RoZXIgZGF0YSBiZXNpZGVzIHRoZSBkYXRhIHVzZWQgaW4gdGhlIHRyYWluaW5nIHNldCB0byBidWlsZCB0aGUgbW9kZWwuIElkZWFsbHkgeW91IHdvdWxkIGFsc28gd2FudCBhIGNvbXBsZXRlbHkgaW5kZXBlbmRlbnQgZGF0YXNldCB0byBmdXJ0aGVyIHRlc3QgdGhlIHBlcmZvcm1hbmNlIG9mIHlvdXIgbW9kZWwuCgpbSGVyZV0oaHR0cHM6Ly9tYWNoaW5lbGVhcm5pbmdtYXN0ZXJ5LmNvbS9kaWZmZXJlbmNlLXRlc3QtdmFsaWRhdGlvbi1kYXRhc2V0cy8pe3RhcmdldD0iX2JsYW5rIn0gaXMgYSBncmVhdCBkZXNjcmlwdGlvbiBvZiB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0ZXN0aW5nIGFuZCB0cmFpbmluZyBkYXRhc2V0cy4KCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjQwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwic3BsaXQucG5nIikpCmBgYApXZSB3aWxsIHVzZSB0aGUgYHJzYW1wbGVgIHBhY2thZ2UgdG8gcGVyZm9ybSB0aGlzIHN0ZXAuCgpUaGVgaW5pdGlhbF9zcGxpdCgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gc3BlY2lmeSBob3cgd2Ugd2FudCB0byBzcGxpdCBvdXIgZGF0YS4gVHlwaWNhbGx5IGRhdGEgaXMgc3BsaXQgaW50byAzLzQgZm9yIHRyYWluaW5nIGFuZCAxLzQgZm9yIHRlc3RpbmcuVGhpcyBpcyB0aGUgZGVmYXVsdCBwcm9wb3J0aW9uIGFuZCBkb2VzIG5vdCBuZWVkIHRvIGJlIHNwZWNpZmllZC4gSG93ZXZlciB5b3UgY2FuIGNoYW5nZSB0aGUgcHJvcG9ydGlvbiB1c2luZyB0aGUgYHByb3BgIGFyZ3VtZW50LCB3aGljaCB3ZSB3aWxsIGRvIHRoYXQgaGVyZSBmb3IgaWxsdXN0cmF0aXZlIHB1cnBvc2VzLiBZb3UgY2FuIGFsc28gc3BlY2lmeSBhIHZhcmlhYmxlIHRvIHN0cmF0aWZ5IGJ5IHdpdGggdGhlIGBzdHJhdGFgIGFyZ3VtZW50LiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3UgaGF2ZSBpbWJhbGFuY2VkIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgeW91IHdvdWxkIGxpa2UgdG8gaW50ZW50aW9uYWxseSBtYWtlIHN1cmUgdGhhdCB0aGVyZSBhcmUgc2ltaWxhciBudW1iZXIgb2Ygc2FtcGxlcyBvZiB0aGUgcmFyZXIgY2F0ZWdvcmllcyBpbiBib3RoIHRoZSB0ZXN0aW5nIGFuZCB0cmFpbmluZyBzZXRzLiBPdGhlcndpc2UgdGhlIHNwbGl0IGlzIHBlcmZvcm1lZCByYW5kb21seS4gCgo+IFRoZSBzdHJhdGEgYXJndW1lbnQgY2F1c2VzIHRoZSByYW5kb20gc2FtcGxpbmcgdG8gYmUgY29uZHVjdGVkIHdpdGhpbiB0aGUgc3RyYXRpZmljYXRpb24gdmFyaWFibGUuIFRoZSBjYW4gaGVscCBlbnN1cmUgdGhhdCB0aGUgbnVtYmVyIG9mIGRhdGEgcG9pbnRzIGluIHRoZSB0cmFpbmluZyBkYXRhIGlzIGVxdWl2YWxlbnQgdG8gdGhlIHByb3BvcnRpb25zIGluIHRoZSBvcmlnaW5hbCBkYXRhIHNldC4KCkluIHRoZSBjYXNlIHdpdGggb3VyIGRhdGFzZXQsIHBlcmhhcHMgd2Ugd291bGQgbGlrZSBvdXIgdHJhaW5pbmcgc2V0IHRvIGhhdmUgc2ltaWxhciBwcm9wb3J0aW9ucyBvZiBtb25pdG9ycyBmcm9tIGVhY2ggb2YgdGhlIHN0YXRlcyBhcyBpbiB0aGUgaW5pdGlhbCBkYXRhLiBUaGlzIG1pZ2h0IGJlIHVzZWZ1bCBpZiB3ZSB3YW50IG91ciBtb2RlbCB0byBiZSBnZW5lcmFsaXphYmxlIGFjcm9zcyBhbGwgb2YgdGhlIHN0YXRlcy4KCldlIGNhbiBzZWUgdGhhdCBpbmRlZWQgdGhlcmUgYXJlIGRpZmZlcmVudCBwcm9wb3J0aW9ucyBvZiBtb25pdG9ycyBpbiBlYWNoIHN0YXRlIGJ5IHVzaW5nIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcHlyYCBwYWNrYWdlLiAKCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CiMgU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKY291bnQocG0sIHN0YXRlKSAlPiUKICBwcmludChuID0gMWUzKQpgYGAKIyMjIwoKSWYgb3VyIGRhdGFzZXQgd2VyZSBsYXJnZSBlbm91Z2ggaXQgbWlnaHQgYmUgbmljZSB0aGVuIHRvIHN0cmF0aWZ5IGJ5IHN0YXRlLCBidXQgb3VyIGRhdGEgaXMgdW5mb3J0dW5hdGVseSBub3QgbGFyZ2UgZW5vdWdoLiBXZSB3aWxsIHNob3cgaG93IG9uZSB3b3VsZCBkbyB0aGlzIHRob3VnaCBmb3IgaWxsdXN0cmF0aXZlIHB1cnBvc2VzLiBUaGlzIG9wdGlvbiBpcyBvZnRlbiBtb3JlIGltcG9ydGFudCBmb3IgY2xhc3NpZmljYXRpb24gYXBwbGljYXRpb25zIG9mIG1hY2hpbmUgbGVhcm5pbmcgdGhhbiBpdCBpcyBmb3IgcHJlZGljdGlvbi4KClNpbmNlIHRoZSBzcGxpdCBpcyBwZXJmb3JtZWQgcmFuZG9tbHksIGl0IGlzIGEgZ29vZCBpZGVhIHRvIHVzZSB0aGUgYHNldC5zZWVkKClgIGJhc2UgZnVuY3Rpb24gdG8gZW5zdXJlIHRoYXQgaWYgeW91ciByZXJ1biB5b3VyIGNvZGUgdGhhdCB5b3VyIHNwbGl0IHdpbGwgYmUgdGhlIHNhbWUgbmV4dCB0aW1lLiBXZSBjYW4gc2VlIHRoZSBudW1iZXIgb2YgbW9uaXRvcnMgaW4gb3VyIHRyYWluaW5nLCB0ZXN0aW5nLCBhbmQgb3JpZ2luYWwgZGF0YSBieSB0eXBpbmcgaW4gdGhlIG5hbWUgb2Ygb3VyIHNwbGl0IG9iamVjdC4gVGhlIHJlc3VsdCB3aWxsIGxvb2sgbGlrZSB0aGlzOgo8dHJhaW5pbmcgZGF0YSBzYW1wbGUgbnVtYmVyLCB0ZXN0aW5nIGRhdGEgc2FtcGxlIG51bWJlciwgb3JpZ2luYWwgc2FtcGxlIG51bWJlcj4gCgpgYGB7cn0Kc2V0LnNlZWQoMTIzNCkKcG1fc3BsaXQgPC1yc2FtcGxlOjppbml0aWFsX3NwbGl0KGRhdGEgPSBwbSwgcHJvcCA9IDIvMykKcG1fc3BsaXQKCiMgSWYgc3RyYXRpZnlpbmc6CiMgcG1fc3BsaXRfc3RyYXRhIDwtcnNhbXBsZTo6aW5pdGlhbF9zcGxpdChkYXRhID0gcG0sIHByb3AgPSAyLzMsIHN0cmF0YSA9ICJzdGF0ZSIpCgpgYGAKCkltcG9ydGFudGx5IHRoZSBgaW5pdGlhbF9zcGxpdGAgZnVuY3Rpb24gb25seSBkZXRlcm1pbmVzIHdoYXQgcm93cyBvZiBvdXIgcG0gZGF0YSBmcmFtZSBzaG91bGQgYmUgYXNzaWduZWQgZm9yIHRyYWluaW5nIG9yIHRlc3RpbmcsIGl0IGRvZXMgbm90IGFjdHVhbGx5IHNwbGl0IHRoZSBkYXRhLiAKClRvIGV4dHJhY3QgdGhlIHRlc3RpbmcgYW5kIHRyYWluaW5nIGRhdGEgd2UgY2FuIHVzZSB0aGUgYHRyYWluaW5nKClgIGFuZCBgdGVzdGluZygpYCBmdW5jdGlvbnMgYWxzbyBvZiB0aGUgYHJzYW1wbGVgIHBhY2thZ2UuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQogdHJhaW5fcG0gPC1yc2FtcGxlOjp0cmFpbmluZyhwbV9zcGxpdCkKIHRlc3RfcG0gPC1yc2FtcGxlOjp0ZXN0aW5nKHBtX3NwbGl0KQogCiMgU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKY291bnQodHJhaW5fcG0sIHN0YXRlKQpjb3VudCh0ZXN0X3BtLCBzdGF0ZSkKYGBgCiMjIyMKCgoKIyMjIFZhcmlhYmxlIFJvbGUgQXNzaWdubWVudCBhbmQgUHJlcHJvY2Vzc2luZwoKSW4gdGlkeW1vZGVscyB3ZSB3aWxsIGNyZWF0ZSBhIHJlY2lwZSwgd2hpY2ggaXMgYSBzdGFuZGFyZGl6ZWQgZm9ybWF0IGZvciBhIHNlcXVlbmNlIG9mIHN0ZXBzIGZvciBwcm9jZXNzaW5nIHRoZSBkYXRhLgoKVGhpcyBjYW4gYmUgdmVyeSB1c2VmdWwgYmVjYXVzZSBpdCBtYWtlcyB0ZXN0aW5nIG91dCBkaWZmZXJlbnQgcHJlLXByb2Nlc3Npbmcgc3RlcHMgb3IgZGlmZmVyZW50IGFsZ29yaXRobXMgd2l0aCB0aGUgc2FtZSBwcmUtcHJvY2Vzc2luZyB2ZXJ5IGVhc3kgYW5kIHJlcHJvZHVjaWJsZS4KCioqQ3JlYXRpbmcgYSByZWNpcGUgc3BlY2lmaWVzIGhvdyBhIGRhdGFmcmFtZSBvZiBwcmVkaWN0b3JzIHNob3VsZCBiZSBjcmVhdGVkICAtIGl0IHNwZWNpZmllcyB3aGF0ICB2YXJpYWJsZXMgdG8gYmUgdXNlZCAgYW5kIHRoZSAgcHJlcHJvY2Vzc2luZyBzdGVwcyAgYnV0IGl0IGRvZXMgbm90IGV4ZWN1dGUgdGhlc2Ugc3RlcHMgb3IgY3JlYXRlIHRoZSBkYXRhZnJhbWUgb2YgcHJlZGljdG9ycy4qKgoKIyMjIyBMaXN0IHRoZSBpbmdyZWRpZW50cyAvIHNwZWNpZnkgdGhlIHZhcmlhYmxlcyB3aXRoIHRoZSBgcmVjaXBlKClgIGZ1bmN0aW9uCgpUaGUgZmlyc3QgdGhpbmcgdG8gZG8gdG8gY3JlYXRlIGEgcmVjaXBlIGlzIHRvIHNwZWNpZnkgd2hpY2ggdmFyaWFibGVzIHdlIHdpbGwgYmUgdXNpbmcgYXMgb3VyIG91dGNvbWUgYW5kIHByZWRpY3RvcnMgdXNpbmcgdGhlIGByZWNpcGUoKWAgZnVuY3Rpb24uIEluIHRlcm1zIG9mIHRoZSBtZXRhcGhvciBvZiBiYWtpbmcsIHdlIGNhbiB0aGluayBvZiB0aGlzIGFzIGxpc3Rpbmcgb3VyIGluZ3JlZGllbnRzLiBUaGUgbmFtaW5nIGNvbnZlbnRpb24gZm9yIHJlY2lwZSBvYmplY3QgbmFtZXMgaXMgYCpfcmVjYCBvciBgcmVjYC4gCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI0MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsInJlY2lwZXMxLnBuZyIpKQpgYGAKCgpJbiBvdXIgY2FzZSByZWNhbGwgdGhhdCBvdXIgYHZhbHVlYCB2YXJpYWJsZSwgd2hpY2ggaXMgdGhlIGF2ZXJhZ2UgYW5udWFsIGdyYXZpbWV0cmljIG1vbml0b3IgUE1+Mi41fiBjb25jZW50cmF0aW9uIGluIHVnL21eM14uIE91ciBwcmVkaWN0b3JzIGFyZSBhbGwgdGhlIG90aGVyIHZhcmlhYmxlcyBleGNlcHQgdGhlIG1vbml0b3IgSUQsIHdoaWNoIGlzIGFuIGBpZGAgdmFyaWFibGUuCgpUaGUgcmVhc29uIG5vdCB0byBpbmNsdWRlIHRoaXMgdmFyaWFibGUgaXMgYmVjYXVzZSB0aGlzIHZhcmlhYmxlIGluY2x1ZGVzIHRoZSBjb3VudHkgbnVtYmVyIGFuZCBhIG51bWJlciBkZXNpZ25hdGluZyB3aGljaCBwYXJ0aWN1bGFyIG1vbml0b3IgdGhlIHZhbHVlcyBjYW1lIGZyb20gb2YgdGhlIG1vbml0b3JzIHRoZXJlIGFyZSBpbiB0aGF0IGNvdW50eS4gU2luY2UgdGhpcyBudW1iZXIgaXMgYXJiaXRyYXJ5IGFuZCB0aGUgY291bnR5IGluZm9ybWF0aW9uIGlzIGFsc28gZ2l2ZW4gaW4gdGhlIGRhdGEsIGFuZCB0aGUgZmFjdCB0aGF0IGVhY2ggbW9uaXRvciBvbmx5IGhhcyBvbmUgdmFsdWUgaW4gdGhlIGB2YWx1ZWAgdmFyaWFibGUsIG5vdGhpbmcgaXMgZ2FpbmVkIGJ5IGluY2x1ZGluZyB0aGlzIHZhcmlhYmxlIGFuZCBpdCBtYXkgaW5zdGVhZCBpbnRyb2R1Y2Ugbm9pc2UuIEhvd2V2ZXIsIGl0IGlzIHVzZWZ1bCB0byBrZWVwIHRoaXMgZGF0YSB0byB0YWtlIGEgbG9vayBhdCB3aGF0IGlzIGhhcHBlbmluZyBsYXRlci4gV2Ugd2lsbCBzaG93IHlvdSB3aGF0IHRvIGRvIGluIHRoaXMgY2FzZSBpbiBqdXN0IGEgYml0LgoKVGhlIHNpbXBsZXN0IHJlY2lwZSB3aXRoIG5vIHByZXByb2Nlc3Npbmcgc3RlcHMsIHdvdWxkIGJlIHRvIHNpbXBseSBsaXN0IHRoZSBvdXRjb21lIGFuZCBwcmVkaWN0b3IgdmFyaWFibGVzLgoKV2UgY2FuIGRvIHNvIGluIHR3byB3YXlzOiAgCgoxKSBVc2luZyBmb3JtdWxhIG5vdGF0aW9uICAKMikgQXNzaWduaW5nIHJvbGVzIHRvIGVhY2ggdmFyaWFibGUgIAoKTGV0J3MgbG9vayBhdCB0aGUgZmlyc3Qgd2F5IHVzaW5nIGZvcm11bGEgbm90YXRpb24sIHdoaWNoIGxvb2tzIGxpa2UgdGhpczogIAoKb3V0Y29tZShzKSB+IHByZWRpY3RvcihzKSAgCgpJZiBpbiB0aGUgY2FzZSBvZiBtdWx0aXBsZSBwcmVkaWN0b3JzIG9yIGEgbXVsdGl2YXJpYXRlIHNpdHVhdGlvbiB3aXRoIHR3byBvdXRjb21lcywgdXNlIGEgcGx1cyBzaWduICAKCm91dGNvbWUxICsgb3V0Y29tZTIgfiBwcmVkaWN0b3IxICsgcHJlZGljdG9yMiAgCgpJZiB3ZSB3YW50IHRvIGluY2x1ZGUgYWxsIHByZWRpY3RvcnMgd2UgY2FuIHVzZSBhIHBlcmlvZCBsaWtlIHNvOiAgCgpvdXRjb21lX3ZhcmlhYmxlX25hbWUgfiAuICAKCk5vdyB3aXRoIG91ciBkYXRhIHdlIHdpbGwgc3RhcnQgYnkgbWFraW5nIGEgcmVjaXBlIGZvciBvdXIgdHJhaW5pbmcgZGF0YS4gSW4gdGhlIHNpbXBsZXN0IGNhc2Ugd2UgbWlnaHQgdXNlIGFsbCBwcmVkaWN0b3JzIGxpa2UgdGhpczoKCmBgYHtyfQoKc2ltcGxlX3JlYyA8LXRyYWluX3BtICU+JQogIHJlY2lwZXM6OnJlY2lwZSh2YWx1ZSB+IC4pCgpzaW1wbGVfcmVjCmBgYAoKCkhvd2V2ZXIsIHRvIGRlYWwgd2l0aCB0aGUgaWQgdmFyaWFibGUgd2UgY291bGQgdXNlIHRoZSBgdXBkYXRlX3JvbGUoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWNpcGVzYCBwYWNrYWdlOgoKYGBge3J9CgpzaW1wbGVfcmVjIDwtdHJhaW5fcG0gJT4lCiAgcmVjaXBlczo6cmVjaXBlKHZhbHVlIH4gLikgJT4lCiAgcmVjaXBlczo6dXBkYXRlX3JvbGUoaWQsIG5ld19yb2xlID0gImlkIHZhcmlhYmxlIikKCnNpbXBsZV9yZWMKYGBgCgpXZSBjb3VsZCBhbHNvIHNwZWNpZnkgdGhlIG91dGNvbWUgYW5kIHByZWRpY3RvcnMgaW4gdGhlIHNhbWUgd2F5IGFzIHRoZSBpZCB2YXJpYWJsZS4gUGxlYXNlIHNlZSBbaGVyZV0oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yZWNpcGVzL3JlZmVyZW5jZS9yZWNpcGUuaHRtbCkgZm9yIGV4YW1wbGVzIG9mIG90aGVyIHJvbGVzIGZvciB2YXJpYWJsZXMuIFRoZSByb2xlIGNhbiBiZSBhY3R1YWxseSBiZSBhbnkgdmFsdWUuIAoKVGhlIG9yZGVyIGlzIGltcG9ydGFudCBoZXJlLCBhcyB3ZSBmaXJzdCBtYWtlIGFsbCB2YXJpYWJsZXMgcHJlZGljdG9ycyBhbmQgdGhlbiBvdmVycmlkZSB0aGlzIHJvbGUgZm9yIHRoZSBvdXRjb21lIGFuZCBpZCB2YXJpYWJsZS4gV2Ugd2lsbCB1c2UgdGhlIGBldmVyeXRoaW5nKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gc3RhcnQgd2l0aCBhbGwgb2YgdGhlIHZhcmlhYmxlcyBpbiBgdHJhaW5fcG1gLgoKYGBge3J9CgpzaW1wbGVfcmVjIDwtcmVjaXBlKHRyYWluX3BtKSAlPiUKICAgIHVwZGF0ZV9yb2xlKGV2ZXJ5dGhpbmcoKSwgbmV3X3JvbGUgPSAicHJlZGljdG9yIiklPiUKICAgIHVwZGF0ZV9yb2xlKHZhbHVlLCBuZXdfcm9sZSA9ICJvdXRjb21lIiklPiUKICAgIHVwZGF0ZV9yb2xlKGlkLCBuZXdfcm9sZSA9ICJpZCB2YXJpYWJsZSIpCgpzaW1wbGVfcmVjCgpgYGAKCklmIHdlIHdhbnQgdG8gdGFrZSBhIGxvb2sgYXQgb3VyIGZvcm11bGEgZnJvbSBvdXIgcmVjaXBlIHdlIGNhbiBkbyB1c2UgdGhlIGBmb3JtdWxhKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UuCgpgYGB7cn0KZm9ybXVsYShzaW1wbGVfcmVjKQpgYGAKCldlIGNhbiBhbHNvIHZpZXcgb3VyIHJlY2lwZSBpbiBtb3JlIGRldGFpbCB1c2luZyB0aGUgYmFzZSBgc3VtbWFyeSgpYCBmdW5jdGlvbi4KCmBgYHtyfQpzdW1tYXJ5KHNpbXBsZV9yZWMpCmBgYAoKIyMjIyBMaXN0IHRoZSBwcmVwcm9jZXNzaW5nIHN0ZXBzIHVzaW5nIHRoZSBzdGVwIGZ1bmN0aW9ucyBvZiB0aGUgYHJlY2lwZWAgcGFja2FnZQoKVGhlIG90aGVyIHRoaW5nIHRoZSByZWNpcGVzIHBhY2thZ2UgYWxsb3dzIGZvciBpcyBzcGVjaWZ5aW5nIHByZS1wcm9jZXNzaW5nIHN0ZXBzIHVzaW5nIGEgdmFyaWV0eSBvZiBgc3RlcCooKWAgZnVuY3Rpb25zLgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNDAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJyZWNpcGVzMi5wbmciKSkKYGBgCgoKKipUaGlzIFtsaW5rXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JlY2lwZXMvcmVmZXJlbmNlL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gYW5kIHRoaXMgW2xpbmtdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yZWNpcGVzL3JlY2lwZXMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHNob3cgdGhlIG1hbnkgb3B0aW9ucyBmb3IgcmVjaXBlIHN0ZXAgZnVuY3Rpb25zLioqCgo8dT5UaGVyZSBhcmUgc3RlcCBmdW5jdGlvbnMgZm9yIGEgdmFyaWV0eSBvZiBwdXJwb3Nlczo8L3U+CgoxKSBbKipJbXB1dGF0aW9uKipdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ltcHV0YXRpb25fKHN0YXRpc3RpY3MpKXt0YXJnZXQ9Il9ibGFuayJ9ICAtLSB3aGljaCBtZWFucyBmaWxsaW5nIGluIG1pc3NpbmcgdmFsdWVzIGJhc2VkIG9uIHRoZSBleGlzdGluZyBkYXRhIAoyKSBbKipUcmFuc2Zvcm1hdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EYXRhX3RyYW5zZm9ybWF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSAgLS0gd2hpY2ggbWVhbnMgY2hhbmdpbmcgYWxsIHZhbHVlcyBvZiBhIHZhcmlhYmxlIGluIHRoZSBzYW1lIHdheSwgdHlwaWNhbGx5IHRvIG1ha2UgaXQgbW9yZSBub3JtYWwgb3IgZWFzaWVyIHRvIGludGVycHJldCkgIAozKSBbKipEaXNjcmV0aXphdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EaXNjcmV0aXphdGlvbl9vZl9jb250aW51b3VzX2ZlYXR1cmVzKSAtLSB3aGljaCBtZWFucyBjb252ZXJ0aW5nIGNvbnRpbnVvdXMgdmFsdWVzIGludG8gZGlzY3JldGUgb3Igbm9taW5hbCB2YWx1ZXMgLSBiaW5uaW5nIGZvciBleGFtcGxlIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHBvc3NpYmxlIGxldmVscykgIChIb3dldmVyIHRoaXMgaXMgZ2VuZXJhbGx5IG5vdCBhZHZpc2FibGUhKQo0KSBbKipFbmNvZGluZyAvIENyZWF0aW5nIER1bW15IFZhcmlhYmxlcyoqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EdW1teV92YXJpYWJsZV8oc3RhdGlzdGljcykpIC0tIHdoaWNoIG1lYW5zIGNyZWF0aW5nIGEgbnVtZXJpYyBjb2RlIGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKWyoqTW9yZSBvbiBEdW1teSBWYXJpYWJsZXMgYW5kIG9uZSBob3QgZW5jb2RpbmcqKl0oaHR0cHM6Ly9tZWRpdW0uY29tL3AvYjU4NDBiZTNjNDFhL3Jlc3BvbnNlcy9zaG93KQo1KSBbKipEYXRhIHR5cGUgY29udmVyc2lvbnMqKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2hhYmxhci92aWduZXR0ZXMvY29udmVydC5odG1sKSAtLSB3aGljaCBtZWFucyBjaGFuZ2luZyBmcm9tIGludGVnZXIgdG8gZmFjdG9yIG9yIG51bWVyaWMgdG8gZGF0ZSBldGMuCjYpIFsqKkludGVyYWN0aW9uKipdKGh0dHBzOi8vc3RhdGlzdGljc2J5amltLmNvbS9yZWdyZXNzaW9uL2ludGVyYWN0aW9uLWVmZmVjdHMvKSB0ZXJtIGFkZGl0aW9uIHRvIHRoZSBtb2RlbCAtLSB3aGljaCBtZWFucyB0aGF0IHdlIHdvdWxkIGJlIG1vZGVsaW5nIGZvciBwcmVkaWN0b3JzIHRoYXQgd291bGQgaW5mbHVlbmNlIHRoZSBjYXBhY2l0eSBvZiBlYWNoIG90aGVyIHRvIHByZWRpY3QgdGhlIG91dGNvbWUKNykgWyoqTm9ybWFsaXphdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Ob3JtYWxpemF0aW9uXyhzdGF0aXN0aWNzKSkgLS0gd2hpY2ggbWVhbnMgY2VudGVyaW5nIGFuZCBzY2FsaW5nIHRoZSBkYXRhIHRvIGEgc2ltaWxhciByYW5nZSBvZiB2YWx1ZXMKOCkgWyoqRGltZW5zaW9uYWxpdHkgUmVkdWN0aW9uLyBTaWduYWwgRXh0cmFjdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EaW1lbnNpb25hbGl0eV9yZWR1Y3Rpb24pIC0tIHdoaWNoIG1lYW5zIG1hdGhlbWF0aWNhbGx5IG9idGFpbmluZyBhIG5ldyBzbWFsbGVyIHNldCBvZiB2YXJpYWJsZXMgdGhhdCBjYXB0dXJlIHRoZSB2YXJpYXRpb24gb3Igc2lnbmFsIGluIHRoZSBvcmlnaW5hbCB2YXJpYWJsZXMgKGV4LiBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIGFuZCBJbmRlcGVuZGVudCBDb21wb25lbnQgQW5hbHlzaXMpCjkpICoqRmlsdGVyaW5nKiogLS0gRmlsdGVyaW5nIG9wdGlvbnMgZm9yIHJlbW92aW5nIHZhcmlhYmxlcyAoZXguIHJlbW92ZSB2YXJpYWJsZXMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgdG8gb3RoZXJzIG9yIHJlbW92ZSB2YXJpYWJsZXMgd2l0aCB2ZXJ5IGxpdHRsZSB2YXJpYW5jZSBhbmQgdGhlcmVmb3JlIGxpa2VseSBsaXR0bGUgcHJlZGljdGl2ZSBjYXBhY2l0eSkKMTApIFsqKlJvdyBvcGVyYXRpb25zKipdKGh0dHBzOi8vdGFydGFydXMub3JnL2dhcmV0aC9tYXRocy9MaW5lYXJfQWxnZWJyYS9yb3dfb3BlcmF0aW9ucy5wZGYpIC0tIHdoaWNoIG1lYW5zIHBlcmZvcm1pbmcgZnVuY3Rpb25zIG9uIHRoZSB2YWx1ZXMgd2l0aGluIHRoZSByb3dzICAoZXguIHJlYXJyYW5naW5nLCBmaWx0ZXJpbmcsIGltcHV0aW5nKQoxMSkgKipDaGVja2luZyBmdW5jdGlvbnMqKiAtLSBTYW5pdHkgY2hlY2tzIHRvIGxvb2sgZm9yIG1pc3NpbmcgdmFsdWVzLCB0byBsb29rIGF0IHRoZSB2YXJpYWJsZSBjbGFzc2VzIGV0Yy4KCkFsbCBvZiB0aGUgc3RlcCBmdW5jdGlvbnMgbG9vayBsaWtlIGBzdGVwXypgIGV4Y2VwdCBmb3IgdGhlIGNoZWNrIGZ1bmN0aW9ucyB3aGljaCBsb29rIGxpa2UgYGNoZWNrXypgLgoKVGhlcmUgYXJlIHNldmVyYWwgd2F5cyB0byBzZWxlY3Qgd2hhdCB2YXJpYWJsZXMgdG8gYXBwbHkgc3RlcHMgdG86ICAKMSkgdGlkeXNlbGVjdCBtZXRob2RzOiBgY29udGFpbnMoKWAsIGBtYXRjaGVzKClgLCBgc3RhcnRzX3dpdGgoKWAsIGBlbmRzX3dpdGgoKWAsIGBldmVyeXRoaW5nKClgLCBgbnVtX3JhbmdlKClgICAKMikgYmFzZWQgb24gdGhlIHR5cGU6IGBhbGxfbm9taW5hbCgpYCwgYGFsbF9udW1lcmljKClgICwgYGhhc190eXBlKClgIAozKSBiYXNlZCBvbiB0aGUgcm9sZTogYGFsbF9wcmVkaWN0b3JzKClgLCBgYWxsX291dGNvbWVzKClgLCBgaGFzX3JvbGUoKWAKNCkgbmFtZSAtIHVzZSB0aGUgYWN0dWFsIG5hbWUgb2YgdGhlIHZhcmlhYmxlL3ZhcmlhYmxlcyBvZiBpbnRlcmVzdCAgCgoKTGV0J3MgdHJ5IGFkZGluZyBzb21lIHN0ZXBzIHRvIG91ciByZWNpcGUuCgpXZSBtaWdodCBjb25zaWRlciBsb2cgdHJhbnNmb3JtaW5nIG91ciBwb3B1bGF0aW9uIGFuZCBhcmVhIHZhcmlhYmxlcyAodGhhdCBhcmVuJ3QgZGVuc2l0aWVzKSAtIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSByYW5nZSBvZiB0aGVzZSB2YXJpYWJsZXMuCmBgYHtyfQpwbSAlPiUKICBzZWxlY3QobWF0Y2hlcygiX3BvcHxfYXJlYSIpKSAlPiUKICBtYXAocmFuZ2UpCmBgYApXZSBjYW4gc2VlIHRoYXQgdGhlIHJhbmdlIGZvciBlYWNoIG9mIHRoZXNlIHZhcmlhYmxlcyBpcyBxdWl0ZSBsYXJnZSwgd2UgY2FuIGxvZyB0cmFuc2Zvcm0gdGhpcyBkYXRhIHVzaW5nIHRoZSBgc3RlcF9sb2coKWAgZnVuY3Rpb24gb2YgdGhlIGByZWNpcGVzYCBwYWNrYWdlLgoKV2Ugd291bGQgYWxzbyB3YW50IHRvIHBvdGVudGlhbGx5IG9uZSBob3QgZW5jb2RlIHNvbWUgb2Ygb3VyIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBzbyB0aGF0IHRoZXkgY2FuIGJlIHVzZWQgd2l0aCBjZXJ0YWluIGFsZ29yaXRobXMuIFdlIGNhbiBkbyB0aGlzIHdpdGggdGhlIGBzdGVwX2R1bW15KClgIGZ1bmN0aW9uIGFuZCB0aGUgYG9uZV9ob3QgPSBUUlVFYCBhcmd1bWVudC4gT3VyIGZpcHMgdmFyaWFibGUgaW5jbHVkZXMgYSBudW1lcmljIGNvZGUgZm9yIHN0YXRlIGFuZCBjb3VudHkgLSBhbmQgdGhlcmVmb3JlIGlzIGVzc2VudGlhbGx5IGEgcHJveHkgZm9yIGNvdW50eS4gIFNpbmNlIHdlIGFscmVhZHkgaGF2ZSBjb3VudHksIHdlIHdpbGwganVzdCB1c2UgaXQgYW5kIGtlZXAgdGhlIGZpcHMgaWQgYXMgYW5vdGhlciBJRCB2YXJpYWJsZS4KCldlIGNhbiByZW1vdmUgdGhlIGBmaXBzYCB2YXJpYWJsZSBmcm9tIHRoZSBwcmVkaWN0b3JzIHVzaW5nIGB1cGRhdGVfcm9sZSgpYCB0byBtYWtlIHN1cmUgdGhhdCB0aGUgcm9sZSBpcyBubyBsb25nZXIgYCJwcmVkaWN0b3IiYC4gV2UgY2FuIG1ha2UgdGhlIHJvbGUgYW55dGhpbmcgd2Ugd2FudCBhY3R1YWxseSwgc28gd2Ugd2lsbCBrZWVwIGl0IHNvbWV0aGluZyBpZGVudGlmaWFibGUuCgpXZSBtaWdodCBhbHNvIHdhbnQgdG8gcmVtb3ZlIHZhcmlhYmxlcyB0aGF0IGFwcGVhciB0byBiZSByZWR1bmRhbnQgYW5kIGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIG90aGVycywgYXMgd2Uga25vdyBmcm9tIG91ciBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIHRoYXQgbWFueSBvZiBvdXIgdmFyaWFibGVzIGFyZSBjb3JyZWxhdGVkIHdpdGggb25lIGFub3RoZXIuIFdlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgc3RlcF9jb3JyKClgIGZ1bmN0aW9uLgoKKipJdCBpcyBpbXBvcnRhbnQgdG8gYWRkIHRoZSBzdGVwcyB0byB0aGUgcmVjaXBlIGluIGFuIG9yZGVyIHRoYXQgbWFrZXMgc2Vuc2UganVzdCBsaWtlIHdpdGggYSBjb29raW5nIHJlY2lwZS4qKgoKYGBge3J9CnNpbXBsZV9yZWMgJTw+JQogICNzdGVwX2xvZyhtYXRjaGVzKCJfcG9wfF9hcmVhIikpICU+JQogIHVwZGF0ZV9yb2xlKCJmaXBzIiwgbmV3X3JvbGUgPSAiY291bnR5IGlkIikgJT4lCiAgc3RlcF9kdW1teShzdGF0ZSwgY291bnR5LCBjaXR5LCB6Y3RhKSAlPiUKICBzdGVwX2NvcnIoYWxsX251bWVyaWMoKSwgLSBDTUFRLCAtIGFvZCklPiUKICBzdGVwX256dihhbGxfbnVtZXJpYygpKSAKICAjc3RlcF9kdW1teShzdGF0ZSwgY291bnR5LCBjaXR5LCB6Y3RhKQojICBzdGVwX2R1bW15KHN0YXRlLCBjb3VudHksIGNpdHksIHpjdGEsIG9uZV9ob3QgPSBUUlVFKQogIyBjaGVja19uZXdfdmFsdWVzKGFsbF9wcmVkaWN0b3JzKCkpICU+JQogICNjaGVja19yYW5nZShhbGxfcHJlZGljdG9ycygpKQoKI2NhbiB1c2Ugc3RlcF9ybSgpIHRvIHJlbW92ZSBwcmVkaWN0b3JzCiAgCnNpbXBsZV9yZWMKYGBgCgoKIyMjIE9QVElPTkFMOiBSdW5uaW5nIHRoZSBwcmVwcm9jZXNzaW5nICh0byBzZWUgaXQpCgpUaGUgbmV4dCBtYWpvciBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgaXMgYHByZXAoKWAuCgpUaGlzIGZ1bmN0aW9uIHVwZGF0ZXMgdGhlIHJlY2lwZSBvYmplY3QgYmFzZWQgb24gdGhlIHRyYWluaW5nIGRhdGEuIEl0IGVzdGltYXRlcyBwYXJhbWV0ZXJzIChlc3RpbWF0aW5nIHRoZSByZXF1aXJlZCBxdWFudGl0aWVzIGFuZCBzdGF0aXN0aWNzIHJlcXVpcmVkIGJ5IHRoZSBzdGVwcyBmb3IgdGhlIHZhcmlhYmxlcykgZm9yIHByZXByb2Nlc3NpbmcgYW5kICB1cGRhdGVzIHRoZSBtb2RlbCB0ZXJtcywgYXMgc29tZSBvZiB0aGUgcHJlZGljdG9ycyBtYXkgYmUgcmVtb3ZlZCwgdGhpcyBhbGxvd3MgdGhlIHJlY2lwZSB0byBiZSByZWFkeSB0byB1c2Ugb24gb3RoZXIgZGF0YXNldHMuIEl0IGRvZXNuJ3QgbmVjZXNzYXJpbHkgYWN0dWFsbHkgZXhlY3V0ZSB0aGUgcHJlcHJvY2Vzc2luZyBpdHNlbGYsIGhvd2V2ZXIgd2Ugd2lsbCBzcGVjaWZ5IGluIGFyZ3VtZW50IGZvciBpdCB0byBkbyB0aGlzIHNvIHRoYXQgd2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBwcmVwcm9jZXNzZWQgZGF0YS4KClRoZXJlIGFyZSBzb21lIGltcG9ydGFudCBhcmd1bWVudHMgdG8ga25vdyBhYm91dDoKMSkgdHJhaW5pbmcgLSB5b3UgbXVzdCBzdXBwbHkgYSB0cmFpbmluZyBkYXRhIHNldCB0byBlc3RpbWF0ZSBwYXJhbWV0ZXJzIGZvciBwcmVwcm9jZXNzaW5nIG9wZXJhdGlvbnMgKHJlY2lwZSBzdGVwcykgLSB0aGlzIG1heSBhbHJlYWR5IGJlIGluY2x1ZGVkIGluIHlvdXIgcmVjaXBlIC0gYXMgaXMgdGhlIGNhc2UgZm9yIHVzCjIpIGZyZXNoIC0gaWYgVFJVRSAtIHdpbGwgcmV0cmFpbiBhbmQgZXN0aW1hdGUgcGFyYW1ldGVycyBmb3IgYW55IHByZXZpb3VzIHN0ZXBzIHRoYXQgd2VyZSBhbHJlYWR5IHByZXBwZWQgaWYgeW91IGFkZCBtb3JlIHN0ZXBzIHRvIHRoZSByZWNpcGUKMykgdmVyYm9zZSAtIGlmIGBUUlVFYCBzaG93cyB0aGUgcHJvZ3Jlc3MgYXMgdGhlIHN0ZXBzIGFyZSBldmFsdWF0ZWQgYW5kIHRoZSBzaXplIG9mIHRoZSBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgc2V0CjQpIHJldGFpbiAtIGlmIGBUUlVFYCB0aGVuIHRoZSBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgc2V0IHdpbGwgYmUgc2F2ZWQgd2l0aGluIHRoZSByZWNpcGUgKGFzIHRlbXBsYXRlKS4gVGhpcyBpcyBnb29kIGlmIHlvdSBhcmUgbGlrZWx5IHRvIGFkZCBtb3JlIHN0ZXBzIGFuZCBkb24ndCB3YW50IHRvIHJlcnVuIHRoZSBgcHJlcCgpYCBvbiB0aGUgcHJldmlvdXMgc3RlcHMuIEhvd2V2ZXIgdGhpcyBjYW4gbWFrZSB0aGUgcmVjaXBlIHNpemUgbGFyZ2UuIFRoaXMgaXMgbmVjZXNzYXJ5IGlmIHlvdSB3YW50IHRvIGFjdHVhbGx5IGxvb2sgYXQgdGhlIHByZXByb2Nlc3NlZCBkYXRhLgoKCmBgYHtyfQpwcmVwcGVkX3JlYyA8LSBwcmVwKHNpbXBsZV9yZWMsIHZlcmJvc2UgPSBUUlVFLCByZXRhaW4gPSBUUlVFICkKbmFtZXMocHJlcHBlZF9yZWMpCmBgYAoKVGhlcmUgYXJlIGFsc28gbG90cyBvZiB1c2VmdWwgdGhpbmdzIHRvIGNoZWNrb3V0IGluIHRoZSBvdXRwdXQgb2YgYHByZXAoKWAuCllvdSBjYW4gc2VlOgoxKSB0aGUgYHN0ZXBzYCB0aGF0IHdlcmUgcnVuICAKMikgdGhlIHZhcmlhYmxlIGluZm8gKGB2YXJfaW5mb2ApICAKMykgdGhlIG1vZGVsIGB0ZXJtX2luZm9gCjQpIHRoZSBuZXcgYGxldmVsc2Agb2YgdGhlIHZhcmlhYmxlcyAKNSkgdGhlIG9yaWdpbmFsIGxldmVscyBvZiB0aGUgdmFyaWFibGVzIGBvcmlnX2x2bHNgICAgCjYpIGluZm8gYWJvdXQgdGhlIHRyYWluaW5nIGRhdGEgc2V0IHNpemUgYW5kIGNvbXBsZXRlbmVzcyAoYHRyX2luZm9gKQoKTm90ZTogIFlvdSBtYXkgc2VlIHRoZSBgcHJlcC5yZWNpcGUoKWAgZnVuY3Rpb24gaW4gbWF0ZXJpYWwgdGhhdCB5b3UgcmVhZCBhYm91dCB0aGUgYHJlY2lwZXNgIHBhY2thZ2UuIFRoaXMgaXMgcmVmZXJyaW5nIHRvIHRoZSBgcHJlcCgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UuCgojIyMjIEV4dHJhY3RpbmcgdGhlIHByZXByb2Nlc3NlZCB0cmFpbmluZyBkYXRhCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI0MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsInJlY2lwZXMzLnBuZyIpKQpgYGAKClNpbmNlIHdlIHJldGFpbmVkIG91ciBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgZGF0YSwgd2UgY2FuIHRha2UgYSBsb29rIGF0IGl0IGxpa2UgYnkgdXNpbmcgdGhlIGBqdWljZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgbGlrZSB0aGlzOgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKcHJlcHBlZF90cmFpbjwtIGp1aWNlKHByZXBwZWRfcmVjKQpnbGltcHNlKHByZXBwZWRfdHJhaW4pCmBgYAojIyMjCgoKRm9yIGVhc3kgY29tcGFyaXNvbiBzYWtlIC0gaGVyZSBpcyBvdXIgb3JpZ2luYWwgZGF0YToKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKZ2xpbXBzZShwbSkKYGBgCiMjIyMKCk5vdGljZSBob3cgd2Ugb25seSBoYXZlIDM2IHZhcmlhYmxlcyBub3cgaW5zdGVhZCBvZiA1MCEgVHdvIG9mIHRoZXNlIGFyZSBvdXIgSUQgdmFyaWFibGVzIChgZmlwc2AgYW5kIHRoZSBhY3R1YWwgbW9uaXRvciBJRCAoYGlkYCkpIGFuZCBvbmUgaXMgb3VyIG91dGNvbWUgKGB2YWx1ZWApLiBUaHVzIHdlIG9ubHkgaGF2ZSAzMyBwcmVkaWN0b3JzIG5vdy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdmFyaWFibGVzIHRoYXQgd2Ugbm8gbG9uZ2VyIGhhdmUgYW55IGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gVmFyaWFibGVzIGxpa2UgYHN0YXRlYCBhcmUgZ29uZSBhbmQgb25seSBgc3RhdGVfQ2FsaWZvcm5pYWAgcmVtYWlucyBhcyBpdCB3YXMgdGhlIG9ubHkgc3RhdGUgaWRlbnRpdHkgdG8gaGF2ZSBub256ZXJvIHZhcmlhbmNlLiAgV2UgY2FuIHNlZSB0aGF0IENhbGlmb3JuaWEgaGFkIHRoZSBsYXJnZXN0IG51bWJlciBvZiBtb25pdG9ycyBjb21wYXJlZCB0byB0aGUgb3RoZXIgc3RhdGVzLiBXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGVyZSB3ZXJlIG1vcmUgbW9uaXRvcnMgbGlzdGVkIGFzIGAiTm90IGluIGEgY2l0eSJgIHRoYW4gYW55IGNpdHkuIAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KcG0gJT4lIGNvdW50KHN0YXRlKQpwbSAlPiUgY291bnQoY2l0eSkKYGBgCiMjIyMKCioqTm90ZSoqOiAgUmVjYWxsIHRoYXQgeW91IG11c3Qgc3BlY2lmeSBgcmV0YWluID0gVFJVRWAgYXJndW1lbnQgb2YgdGhlIGBwcmVwKClgIGZ1bmN0aW9uIHRvIHVzZSBganVpY2UoKWAuCgojIyMjIEV4dHJhY3RpbmcgdGhlIHByZXByb2Nlc3NlZCB0ZXN0aW5nIGRhdGEKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjQwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwicmVjaXBlczQucG5nIikpCmBgYAoKTGF0ZXIgb24gaWYgeW91IHdhbnQgdG8gbG9vayBhdCB0aGUgcHJlcHJvY2Vzc2VkIHRlc3RpbmcgZGF0YSB5b3Ugd291bGQgdXNlIHRoZSBgYmFrZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgbGlrZSB0aGlzOgoKSG93ZXZlciB5b3Ugd291bGQgd2FudCB0byBsZWF2ZSB5b3VyIHRlc3RpbmcgZGF0YSBhbG9uZSBhdCB0aGlzIHBvaW50LgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKYmFrZWRfcmVjIDwtIHJlY2lwZXM6OmJha2UocHJlcHBlZF9yZWMsIG5ld19kYXRhID0gdGVzdF9wbSkKZ2xpbXBzZShiYWtlZF9yZWMpCmBgYAojIyMjCgo+IGJha2UoKSB0YWtlcyBhIHRyYWluZWQgcmVjaXBlIGFuZCBhcHBsaWVzIHRoZSBvcGVyYXRpb25zIHRvIGEgZGF0YSBzZXQgdG8gY3JlYXRlIGEgZGVzaWduIG1hdHJpeC4KIGZvciBleGFtcGxlOiAgaXQgYXBwbGllcyB0aGUgY2VudGVyaW5nIHRvIG5ldyBkYXRhIHNldHMgdXNpbmcgdGhlc2UgbWVhbnMgdXNlZCB0byBjcmVhdGUgdGhlIHJlY2lwZQoKCk5vdGU6IGlmIHlvdSB1c2UgdGhlIHNraXAgb3B0aW9uIGZvciBzb21lIG9mIHRoZSBwcmVwcm9jZXNzaW5nIHN0ZXBzLCBiZSBjYXJlZnVsLiBganVpY2UoKWAgd2lsbCBzaG93IGFsbCBvZiB0aGUgcmVzdWx0cyBpZ25vcmluZyBgc2tpcCA9IFRSVUVgLiBgYmFrZSgpYCB3aWxsIG5vdCBuZWNlc3NhcmlseSBjb25kdWN0IHRoZXNlIHN0ZXBzIG9uIHRoZSBuZXcgZGF0YS4gCgoKCiMjIyBTcGVjaWZ5aW5nIHRoZSBNb2RlbAoKU28gZmFyIHdlIGhhdmUgdXNlZCBgcnNhbXBsZWAgdG8gc3BsaXQgdGhlIGRhdGEgYW5kIGByZWNpcGVzYCB0byBhc3NpZ24gdmFyaWFibGUgYW5kIHRvIHNwZWNpZnkgYW5kIHByZXAgb3VyIHByZXByb2Nlc3NpbmcgKGFzIHdlbGwgYXMgdG8gb3B0aW9uYWxseSBleHRyYWN0IHRoZSBwcmVwcm9jZXNzZWQgZGF0YSkuCgpXZSB3aWxsIG5vdyB1c2UgdGhlIGBwYXJzbmlwYCBwYWNrYWdlICh3aGljaCBpcyBzaW1pbGFyIHRvIHRoZSBwcmV2aW91cyBgY2FyZXRgIHBhY2thZ2UgLSBhbmQgaGVuY2Ugd2h5IGl0IGlzIG5hbWVkIGFmdGVyIHRoZSB2ZWdldGFibGUpIHRvIHNwZWNpZnkgb3VyIG1vZGVsLgoKVGhlcmUgYXJlIGZvdXIgYXNwZWN0cyB0byBkZWZpbmUgYWJvdXQgb3VyIG1vZGVsOiAgCjEpIHRoZSAqKnR5cGUqKiBvZiBtb2RlbCAodXNpbmcgc3BlY2lmaWMgZnVudGlvbnMgaW4gcGFyc25pcCBsaWtlIGByYW5kX2ZvcmVzdCgpYCwgYGxvZ2lzdGljX3JlZygpYCBldGMuKSAgCjIpIHRoZSAqKm1vZGUqKiBvZiBsZWFybmluZyAtIGNsYXNzaWZpY2F0aW9uIG9yIHJlZ3Jlc3Npb24gKHVzaW5nIHRoZSBgc2V0X21vZGUoKWAgZnVuY3Rpb24pICAKMykgdGhlIHBhY2thZ2Ugb3IgKiplbmdpbmUqKiB0aGF0IHdlIHdpbGwgdXNlIHRvIGltcGxlbWVudCB0aGUgdHlwZSBvZiBtb2RlbCBzZWxlY3RlZCAodXNpbmcgdGhlIGBzZXRfZW5naW5lKClgIGZ1bmN0aW9uKSAgCjQpIGFueSAqKmFyZ3VtZW50cyoqIG5lY2Vzc2FyeSBmb3IgdGhlIG1vZGVsL3BhY2thZ2Ugc2VsZWN0ZWQgKHVzaW5nIHRoZSBgc2V0X2FyZ3MoKWBmdW5jdGlvbiAtICBmb3IgZXhhbXBsZSB0aGUgYG10cnkgPWAgYXJndW1lbnQgZm9yIHJhbmRvbSBmb3Jlc3Qgd2hpY2ggaXMgdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgdG8gYmUgdXNlZCBhcyBvcHRpb25zIGZvciBzcGxpdHRpbmcgYXQgZWFjaCB0cmVlIG5vZGUpICAKCldlIGFyZSBnb2luZyB0byBzdGFydCBvdXIgYW5hbHlzaXMgd2l0aCBhIGxpbmVhciByZWdyZXNzaW9uIGJ1dCB3ZSB3aWxsIGRlbW9uc3RyYXRlIGhvdyB3ZSBjYW4gdHJ5IGRpZmZlcmVudCBtb2RlbHMuCgpUaGUgZmlyc3QgdGhpbmcgd2UgZG8gaXMgZGVmaW5lIHdoYXQgdHlwZSBvZiBtb2RlbCB3ZSB3b3VsZCBsaWtlIHRvIHVzZS4gU2VlIFtoZXJlXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3BhcnNuaXAvYXJ0aWNsZXMvYXJ0aWNsZXMvTW9kZWxzLmh0bWwKKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb2RlbGluZyBbb3B0aW9uc11pbiBwYXJzbmlwLgoKYGBge3J9ClBNX21vZGVsIDwtIHBhcnNuaXA6OmxpbmVhcl9yZWcoKSAjUE0gZm9yIHBhcnRpY3VsYXRlIG1hdGVyClBNX21vZGVsCmBgYAoKT0suIFNvIGZhciBhbGwgd2UgaGF2ZSB0b2xkIGBwYXJzbmlwYCBpcyB3ZSB3YW50IHRvIHVzZSBhIGxpbmVhciByZWdyZXNzaW9uLi4uICBMZXQncyB0ZWxsIGBwYXJzbmlwYCBtb3JlIGFib3V0IHdoYXQgd2Ugd2FudC4KCldlIHdvdWxkIGxpa2UgdG8gdXNlIHRoZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIG1ldGhvZCB0byBmaXQgb3VyIGxpbmVhciByZWdyZXNzaW9uLiBTbyB3ZSB3aWxsIHRlbGwgYHBhcnNuaXBgIHRoYXQgd2Ugd2FudCB0byB1c2UgdGhlIGBsbWAgcGFja2FnZSB0byBpbXBsZW1lbnQgb3VyIGxpbmVhciByZWdyZXNzaW9uICh0aGVyZSBhcmUgbWFueSBvcHRpb25zIGFjdHVhbGx5LSBzdWNoIGFzIFtgcnN0YW5gXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcnN0YW4vdmlnbmV0dGVzL3JzdGFuLmh0bWwpIFtgZ2xtbmV0YF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dsbW5ldC9pbmRleC5odG1sKSwgW2BrZXJhc2BdKGh0dHBzOi8va2VyYXMucnN0dWRpby5jb20vKSwgYW5kIFtgc3BhcmtseXJgXShodHRwczovL3RoZXJpbnNwYXJrLmNvbS9zdGFydGluZy5odG1sI3N0YXJ0aW5nLXNwYXJrbHlyLWhlbGxvLXdvcmxkKSkuIFdlIHdpbGwgZG8gc28gYnkgdXNpbmcgdGhlIGBzZXRfZW5naW5lKClgIGZ1bmN0aW9uIG9mIHRoZSBgcGFyc25pcGAgcGFja2FnZS4KCmBgYHtyfQpsbV9QTV9tb2RlbCA8LSAKICBQTV9tb2RlbCAgJT4lCiAgcGFyc25pcDo6c2V0X2VuZ2luZSgibG0iKQoKbG1fUE1fbW9kZWwKCmBgYAoKSW4gc29tZSBjYXNlcyBzb21lIHBhY2thZ2VzIGNhbiBkbyBlaXRoZXIgY2xhc3NpZmljYXRpb24gb3IgcHJlZGljdGlvbiwgc28gaXQgaXMgYSBnb29kIGlkZWEgdG8gc3BlY2lmeSB3aGljaCBtb2RlIHlvdSBpbnRlbmQgdG8gcGVyZm9ybS4gWW91IGNhbiBkbyB0aGlzIHdpdGggdGhlIGBzZXRfbW9kZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHBhcnNuaXBgIHBhY2thZ2UsIGJ5IHVzaW5nIGVpdGhlciBgc2V0X21vZGUoImNsYXNzaWZpY2F0aW9uIilgIG9yIGBzZXRfbW9kZSgicmVncmVzc2lvbiIpYC4KCmBgYHtyfQpsbV9QTV9tb2RlbCA8LSAKICBQTV9tb2RlbCAgJT4lCiAgcGFyc25pcDo6c2V0X2VuZ2luZSgibG0iKSAlPiUKICBzZXRfbW9kZSgicmVncmVzc2lvbiIpCgpsbV9QTV9tb2RlbAoKYGBgCgojIyMgRml0dGluZyB0aGUgTW9kZWwgd2l0aCBgd29ya2Zsb3dzYCBhbmQgYHBhcnNuaXBgCgpUbyBmaXQgb3VyIG1vZGVsIHdlIGNvdWxkIHVzZSBgcGFyc25pcGAgYW5kIHRoZW4gYXNzZXNzIG91ciBmaXQgdXNpbmcgdGhlIGB5YXJkc3RpY2tgIHBhY2thZ2UuCgpIb3dldmVyIGEgbmV3ZXIgcGFja2FnZSBjYWxsZWQgYHdvcmtmbG93c2AgYWxsb3dzIHVzIHRvIGtlZXAgdHJhY2sgb2YgYm90aCBvdXIgcHJlcHJvY2Vzc2luZyBzdGVwcyBhbmQgb3VyIG1vZGVsIHNwZWNpZmljYXRpb24uIEl0IGFsc28gYWxsb3dzIHVzIHRvIGltcGxlbWVudCBmYW5jaWVyIG9wdGltaXphdGlvbnMgaW4gYW4gYXV0b21hdGVkIHdheSBhbmQgaXQgaXMgY3VycmVudGx5IGJlaW5nIGRldmVsb3BlZCB0byBhbHNvIGhhbmRsZSBwb3N0LXByb2Nlc3Npbmcgb3BlcmF0aW9ucywgc28gaXQgaXMgZ29vZCB0byBsZWFybiBhYm91dCBpdCEKClNvIHdlIHdpbGwgbm93IGNyZWF0ZSBhIHdvcmtmbG93IHdpdGggdGhlIHJlY2lwZSAob3VyIHByZXByb2Nlc3Npbmcgc3BlY2lmaWNhdGlvbnMpIHRoYXQgd2UgbWFkZSBhbmQgdGhlIG1vZGVsIHRoYXQgd2UganVzdCBzcGVjaWZpZWQuCgpGaXJzdCB3ZSB1c2UgdGhlIGB3b3JrZmxvdygpYCBmdW5jdGlvbiBvZiB0aGUgYHdvcmtmbG93c2AgcGFja2FnZSB0byBjcmVhdGUgYSB3b3JrZmxvdy4KClRoZW4gd2UgYWRkIG91ciByZWNpcGUgd2l0aCB0aGUgYGFkZF9yZWNpcGUoKWAgZnVuY3Rpb24gYW5kIHdlIGFkZCBvdXIgbW9kZWwgd2l0aCB0aGUgYGFkZF9tb2RlbCgpYCBmdW5jdGlvbiBvZiB0aGUgYHdvcmtmbG93c2AgcGFja2FnZS4gCgpOb3RlOiBXZSBkbyBub3QgbmVlZCB0byBhY3R1YWxseSBwcmVwIG91ciByZWNpcGUgYmVmb3JlIHVzaW5nIHdvcmtmbG93cyEKCmBgYHtyfQpQTV93ZmxvdyA8LXdvcmtmbG93czo6d29ya2Zsb3coKSAlPiUKICAgICAgICAgICB3b3JrZmxvd3M6OmFkZF9yZWNpcGUoc2ltcGxlX3JlYykgJT4lCiAgICAgICAgICAgd29ya2Zsb3dzOjphZGRfbW9kZWwobG1fUE1fbW9kZWwpClBNX3dmbG93CmBgYAoKQWgsIG5pY2UuIE5vdGljZSBob3cgaXQgdGVsbHMgdXMgYWJvdXQgYm90aCBvdXIgcHJlcHJvY2Vzc2luZyBzdGVwcyBhbmQgb3VyIG1vZGVsIHNwZWNpZmljYXRpb25zLgoKTm93IHdlIGNhbiBwcmVwYXJlIHRoZSByZWNpcGUgKGVzdGltYXRlIHRoZSBwYXJhbWV0ZXJzKSBhbmQgZml0IHRoZSBtb2RlbCB0byBvdXIgdHJhaW5pbmcgZGF0YSBhbGwgYXQgb25jZS4gUHJpbnRpbmcgdGhlIG91dHB1dCB3ZSBjYW4gc2VlIHRoZSBjb2VmZmljaWVudHMgb2YgdGhlIG1vZGVsLgoKYGBge3J9ClBNX3dmbG93X2ZpdCA8LSBwYXJzbmlwOjpmaXQoUE1fd2Zsb3csIGRhdGEgPSB0cmFpbl9wbSkKUE1fd2Zsb3dfZml0CmBgYAoKT3RoZXJ3aXNlIHdlIGNvdWxkIGhhdmUgZG9uZSB0aGlzIHdpdGhvdXQgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UuIE5vdGljZSBoZXJlIHdlIHdpbGwgdXNlZCB0aGUgcHJlcHBlZCB0cmFpbmluZyBkYXRhIGFzIG9wcG9zZWQgdG8gdGhlIHJhdyB0cmFpbmluZyBkYXRhIHRoYXQgd2UgdXNlZCB3aXRoIHRoZSB3b3JrZmxvdyB3ZSBjcmVhdGVkIHdpdGggYHdvcmtmbG93c2AuCgpgYGB7cn0KUE1fZml0IDwtIGxtX1BNX21vZGVsICU+JSAKICBwYXJzbmlwOjpmaXQodmFsdWUgfi4sIGRhdGEgPXByZXBwZWRfdHJhaW4pCgpgYGAKCiMjIyBMb29raW5nIGF0IG1vZGVsIGZpdCB3aXRoIGBicm9vbWAKClRoZSBgYnJvb21gIHBhY2thZ2UgYWxsb3dzIGZvciBhbiBlYXN5L3RpZHkgd2F5IHRvIGxvb2sgYXQgdGhlIGZpdHRlZCBtb2RlbDogIAoKYHRpZHkoKWAgZ3JhYnMgdGhlIGNvZWZmaWNpZW50cyBmcm9tIHRoZSBtb2RlbCAgCmBnbGFuY2UoKWAgc3VtbWFyaXplcyB0aGUgbW9kZWwgZml0ICAKYGF1Z21lbnQoKWAgZ2l2ZXMgYSAxNTAgcm93IG9ic2VydmF0aW9uIGxldmVsIHN1bW1hcnkgIAoKVGhlc2UgYGJyb29tYCBmdW5jdGlvbnMgY3VycmVudGx5IG9ubHkgd29yayB3aXRoIGBwYXJzbmlwYCBvYmplY3RzIG5vdCByYXcgYHdvcmtmbG93c2Agb2JqZWN0cy4gVG8gdXNlIHRoZXNlIGZ1bmN0aW9ucyB3aXRoIGB3b3JrZmxvd3NgIHdlIG5lZWQgdG8gZmlyc3QgdXNlIHRoZSBgcHVsbF93b3JrZmxvd19maXQoKWAgZnVuY3Rpb24uCgpgYGB7cn0KYnJvb206OnRpZHkoUE1fZml0KQpicm9vbTo6Z2xhbmNlKFBNX2ZpdCRmaXQpCmJyb29tOjphdWdtZW50KFBNX2ZpdCRmaXQpCgoKUE1fd2Zsb3dfZml0ICU+JSAKICBwdWxsX3dvcmtmbG93X2ZpdCgpICU+JSAKICB0aWR5KCkKYGBgCgoKT0ssIHNvIHdlIGhhdmUgZml0IG91ciBtb2RlbCBvbiBvdXIgdHJhaW5pbmcgZGF0YSwgd2hpY2ggbWVhbnMgd2UgaGF2ZSBjcmVhdGVkIGEgbW9kZWwgdG8gcHJlZGljdCB2YWx1ZXMgb2YgYWlyIHBvbGx1dGlvbiBiYXNlZCBvbiB0aGUgcHJlZGljdG9ycyB0aGF0IHdlIGhhdmUgaW5jbHVkZWQuIFlheSEKCgpBdCB0aGlzIHBvaW50IHdlIGNvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBhY2N1cmFjeSBvZiBvdXIgbW9kZWwgcGVyZm9ybWFuY2UsIGJ1dCB3ZSB3aWxsIG9ubHkgaGF2ZSBvbmUgcmVmZXJlbmNlIHBvaW50OiBvdXIgdGVzdGluZyBkYXRhc2V0LiBBbmQgd2UgaGF2ZW4ndCBkb25lIGFueSB0dW5pbmcgb2Ygb3VyIG1vZGVsIG9yIGNyb3NzIHZhbGlkYXRpb24uLi4gc28gZ2VuZXJhbGx5IHNwZWFraW5nIHlvdSA8dT4qKnNob3VsZCBub3QqKjwvdT4gZG8gdGhpcy4gCgpIb3dldmVyIGlmIHlvdSB3ZXJlIHNob3J0IG9uIHRpbWUgeW91IGNvdWxkIGNvbnRpbnVlIGxpa2UgdGhpcy4KCm5lZWQgdHVuZV8qKCksIGZpdF9yZXNhbXBsZXMoKSBvciBsYXN0X2ZpdCgpIHRvIGdldCBhbnkgYXNzZXNzbWVudCBvZiBmaXQuCgoKV2UgY291bGQgc3RvcCBoZXJlIGFuZCB1c2UgdGhlIGB5YXJkc3RpY2tgIHBhY2thZ2UgdG8gZXZhbHVhdGUgcGVyZm9ybWFuY2UuIEZpcnN0IHdlIHdvdWxkIHdhbnQgdG8gZml0IHRoZSBtb2RlbCB3aXRoIGhtbW0gbm90IHN1cmUgaWYgSSB3aWxsIGRvIHRoaXMgb3IganVzdCBza2lwIGFuZCB1c2UgdHVuZSBldmVuIGlmIHdlIGRvbnQgaGF2ZSBhbnkgdHVuaW5nPz8KClVzaW5nIHBhcnNuaXAgd2UgbmVlZCB0byB1c2UgdGhlIGJha2VkIGRhdGEgdGVzdGluZyBkYXRhLi4uIG9yIG5vdD8/PwpgYGB7cn0KIyBsbV9maXQgPC1sbV9QTV9tb2RlbCAlPiUKIyAgIHBhcnNuaXA6OmZpdCh2YWx1ZSB+LixkYXRhID0ganVpY2VkX3JlYykKI3lhcmRzdGljazo6bWV0cmljcyhsbV9maXQsIHRydXRoLCBwcmVkaWN0ZWQpCgojIHZhbHVlc19wcmVkIDwtIAojICAgcHJlZGljdChQTV93Zmxvd19maXQsIGJha2VkX3JlYykgJT4lIAojICAgYmluZF9jb2xzKGJha2VkX3JlYyAlPiUgc2VsZWN0KHZhbHVlLCBmaXBzKSkgCiMgdmFsdWVzX3ByZWQKCgp2YWx1ZXNfcHJlZCA8LSAKICBwcmVkaWN0KFBNX3dmbG93X2ZpdCwgdGVzdF9wbSkgJT4lIAogIGJpbmRfY29scyh0ZXN0X3BtICU+JSBzZWxlY3QodmFsdWUsIGZpcHMpKSAKdmFsdWVzX3ByZWQKI1dpdGggVHVuZSBwYWNrYWdlOgojb3ZlcmFsbGZpdCA8LXR1bmU6Omxhc3RfZml0KFBNX3dmbG93LCBwbV9zcGxpdCkKI2NvdW50KHZhbHVlc19wcmVkLCAucHJlZCkKYGBgCgoKU2F5IHdlIHdlcmUgZG9uZSBvcHRpbWl6aW5nIG91ciBwYXJhbWV0ZXJzIHdlIGNvdWxkIHRoZW4gdXNlIHRoZSBgbGFzdF9maXQoKWAgZnVuY3Rpb24gb2YgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojb3ZlcmFsbGZpdCA8LXR1bmU6Omxhc3RfZml0KFBNX3dmbG93LCBwbV9zcGxpdCkKICMgb3IKI292ZXJhbGxmaXQgPC1QTV93ZmxvdyAlPiUKIyAgdHVuZTo6bGFzdF9maXQocG1fc3BsaXQpCgojI292ZXJhbGxmaXQKYGBgCgpXZSBjb3VsZCBjaGVjayBvdXQgdGVzdCBwZXJmb3JtYW5jZSB1c2luZyB0aGUgYGNvbGxlY3RfbWV0cmljcygpYCBmdW5jdGlvbiBvZiB0aGUgYHR1bmVgIHBhY2thZ2UuCgptb2RlbCBwZXJmb3JtYW5jZSA6aHR0cHM6Ly9tZWRpdW0uY29tL0BsaW1hdmFsbGFudGluL21ldHJpY3MtdG8tbWVhc3VyZS1tYWNoaW5lLWxlYXJuaW5nLW1vZGVsLXBlcmZvcm1hbmNlLWU4Yzk2MzY2NTQ3NgoKYGBge3J9CiN0ZXN0X3BlcmZvcm1hbmNlIDwtIG92ZXJhbGxmaXQgICU+JXR1bmU6OmNvbGxlY3RfbWV0cmljcygpCiN0ZXN0X3BlcmZvcm1hbmNlCmBgYAoKSGVyZSB5b3UgY2FuIHNlZSB0aGUgcHJlZGljdGlvbnMgZm9yIHRoZSB0ZXN0IHNldCAodGhlIDI5MiByb3dzIHdpdGggcHJlZGljaXRpb25zIG91dCBvZiB0aGUgODc2IG9yaWdpbmFsIG1vbml0b3IgdmFsdWVzKSBhbHNvIHVzaW5nIHRoZSBgdHVuZWAgcGFja2FnZSB3aXRoIHRoZSBgY29sbGVjdF9wcmVkaWN0aW9ucygpYCBmdW5jdGlvbi4KCmBgYHtyfQojdGVzdF9wcmVkaWN0aW9ucyA8LSBvdmVyYWxsZml0ICAlPiV0dW5lOjpjb2xsZWN0X3ByZWRpY3Rpb25zKCkKI3ByaW50KHRlc3RfcHJlZGljdGlvbnMsIG49MWUzKQpgYGAKIyMjIwoKCkhvd2V2ZXIgd2Ugd291bGQgcmVhbGx5IHdhbnQgdG8gdHVuZSBwYXJhbWV0ZXJzIGFuZCB1c2UgY3Jvc3MgdmFsaWRhdGlvbiBmb3IgdGhpcy4KCgoKeWFyZHN0aWNrIGNhbid0IHRhbGsgZGlyZWN0bHkgdG8gd29ya2Zsb3dzLi4uIG5lZWQgdHVuZSBmb3IgdGhhdC4uLgoKCgojIyMgQ3Jvc3MgdmFsaWRhdGlvbiBzYW1wbGUgc3BsaXR0aW5nCgpXZSB3aWxsIHVzZSB0aGUgYHJzYW1wbGVgIHBhY2thZ2UgYWdhaW4gaW4gb3JkZXIgdG8gZnVydGhlciBpbXBsZW1lbnQgd2hhdCBhcmUgY2FsbGVkIFtjcm9zcyB2YWxpZGF0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy12YWxpZGF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSB0ZWNobmlxdWVzLiBUaGlzIGlzIGFsc28gY2FsbGVkICoqcmVzYW1wbGluZyoqIG9yICoqcmVwYXJ0aW9uaW5nKiouCk5vdGU6IHdlIGFyZSBub3QgYWN0dWFsbHkgZ2V0dGluZyBuZXcgc2FtcGxlcyBmcm9tIHRoZSB1bmRlcmx5aW5nIGRpc3RyaWJ1dGlvbiBzbyB0aGUgdGVybSByZXNhbXBsaW5nIGlzIGEgYml0IG9mIGEgbWlzbm9tZXIuCgpbQ3Jvc3MgdmFsaWRhdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ3Jvc3MtdmFsaWRhdGlvbl8oc3RhdGlzdGljcykpe3RhcmdldD0iX2JsYW5rIn0gc3BsaXRzIG91ciB0cmFpbmluZyBkYXRhIGludG8gbXVsdGlwbGUgdHJhaW5pbmcgZGF0YSBzZXRzIHRvIGFsbG93IGZvciBhbiBhc3Nlc3NtZW50IG9mIHRoZSBhY2N1cmFjeSBvZiB0aGUgbW9kZWwuCgpIZXJlIGlzIGEgdmlzdWFsaXphdGlvbiBvZiB0aGUgY29uY2VwdCBmb3IgY3Jvc3MgdmFsaWRhdGlvbi9yZXNhbXBsaW5nL3JlcGFydGl0aW9uaW5nIGZyb20gW01heCBLdWhuXShodHRwczovL3Jlc291cmNlcy5yc3R1ZGlvLmNvbS9hdXRob3JzL21heC1rdWhuKXt0YXJnZXQ9Il9ibGFuayJ9OgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJyZXNhbXBsaW5nLnBuZyIpKQpgYGAKClRlY2huaWNhbGx5IGNyZWF0aW5nIG91ciB0ZXN0aW5nIGFuZCB0cmFpbmluZyBzZXQgb3V0IG9mIG91ciBvcmlnaW5hbCB0cmFpbmluZyBkYXRhIGlzIHNvbWV0aW1lcyBjb25zaWRlcmVkIGEgZm9ybSBvZiBbY3Jvc3MgdmFsaWRhdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ3Jvc3MtdmFsaWRhdGlvbl8oc3RhdGlzdGljcykpe3RhcmdldD0iX2JsYW5rIn0gY2FsbGVkIHRoZSBob2xkb3V0IG1ldGhvZC4gQXMgd2UganVzdCBsZWFybmVkIHRoaXMgY2FuIGdpdmUgdXMgYSBiZXR0ZXIgc2Vuc2Ugb2YgdGhlIGFjY3VyYWN5IG9mIG91ciBkYXRhIGluIGEgbW9yZSBnZW5lcmFsaXphYmxlIHdheS4gCgpIb3dldmVyLCB3ZSBjYW4gZG8gYSBiZXR0ZXIgam9iIG9mIG9wdGltaXppbmcgb3VyIG1vZGVsIGZvciBhY2N1cmFjeSBpZiB3ZSBhbHNvIHBlcmZvcm0gYW5vdGhlciB0eXBlIG9mIFtjcm9zcyB2YWxpZGF0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy12YWxpZGF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSBvbiB0aGUgbmV3bHkgZGVmaW5lZCB0cmFpbmluZyBzZXQgdGhhdCB3ZSBqdXN0IGNyZWF0ZWQuIFRoZXJlIGFyZSBtYW55IFtjcm9zcyB2YWxpZGF0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy12YWxpZGF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSBtZXRob2RzIGFuZCBtb3N0IGNhbiBiZSBlYXNpbHkgaW1wbGVtZW50ZWQgdXNpbmcgYHJzYW1wbGVzYCBwYWNrYWdlLiBXZSB3aWxsIHVzZSBhIHZlcnkgcG9wdWxhciBtZXRob2QgY2FsbGVkIGVpdGhlciBbay1mb2xkIG9yIHYtZm9sZCBjcm9zcyB2YWxpZGF0aW9uXShodHRwczovL21hY2hpbmVsZWFybmluZ21hc3RlcnkuY29tL2stZm9sZC1jcm9zcy12YWxpZGF0aW9uLyl7dGFyZ2V0PSJfYmxhbmsifS4gCgpUaGlzIG1ldGhvZCBpbnZvbHZlcyBlc3NlbnRpYWxseSBwcmVmb3JtaW5nIHRoZSBob2xkIG91dCBtZXRob2QgaXRlcmF0aXZlbHkgd2l0aCB0aGUgdHJhaW5pbmcgZGF0YS4gCgpGaXJzdCB0aGUgdHJhaW5pbmcgc2V0IGlzIGRpdmlkZWQgaW50byBrIG9yIHYgZXF1YWxseSBzaXplZCBzbWFsbGVyIHBpZWNlcy4gCgpUaGVuIHRoZSBtb2RlbCBpcyB0cmFpbmVkIG9uIHRoZSBtb2RlbCBvbiBrLTEgb3Igdi0xIHN1YnNldHMgb2YgdGhlIGRhdGEgaXRlcmF0aXZlbHkgKHJlbW92aW5nIGEgZGlmZmVyZW50IHYgb3IgayB1bnRpbGwgYWxsIHBvc3NpYmxlIGstMSBvciB2LTEgc2V0cyBoYXZlIGJlZW4gZXZhbHVhdGVkKSB0byBnZXQgYSBzZW5zZSBvZiB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIG1vZGVsLiBUaGlzIGlzIHJlYWxseSB1c2VmdWwgZm9yIGZpbmUgdHVuaW5nIHNwZWNpZmljIGFzcGVjdHMgb2YgdGhlIG1vZGVsIGluIGEgcHJvY2VzcyBjYWxsZWQgbW9kZWwgdHVuaW5nLgoKCkhlcmUgaXMgYSB2aXN1YWxpemF0aW9uIG9mIGhvdyB0aGUgZm9sZHMgYXJlIGNyZWF0ZWQ6CgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsInZmb2xkLnBuZyIpKQpgYGAKCgpOb3RlOiBQZW9wbGUgdHlwaWNhbGx5IGlnbm9yZSBzcGF0aWFsIGRlcGVuZGVuY2Ugd2l0aCBjcm9zcyB2YWxpZGF0aW9uIG9mIGFpciBwb2xsdXRpb24gbW9uaXRvcmluZyBkYXRhIGluIHRoZSBhaXIgcG9sbHV0aW9uIGZpZWxkLCBzbyB3ZSB3aWxsIGRvIHRoZSBzYW1lLiAgSG93ZXZlciwgaXQgbWlnaHQgbWFrZSBzZW5zZSB0byBsZWF2ZSBvdXQgYmxvY2tzIG9mIG1vbml0b3JzIHJhdGhlciB0aGFuICByYW5kb20gaW5kaXZpZHVhbCBtb25pdG9ycyB0byBoZWxwIGFjY291bnQgZm9yIHNvbWUgc3BhdGlhbCBkZXBlbmRlbmNlLgoKVGhlIFtgdmZvbGRfY3YoKWBdKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vcnNhbXBsZS9yZWZlcmVuY2UvdmZvbGRfY3YuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBmdW5jdGlvbiBvZiB0aGUgYHJzYW1wbGVgIHBhY2thZ2UgY2FuIGJlIHVzZWQgdG8gcGFyc2UgdGhlIHRyYWluaW5nIGRhdGEgaW50byBmb2xkcyBmb3Igay1mb2xkL3YtZm9sZCBjcm9zcyB2YWxpZGF0aW9uLgoKVGhlIGB2YCBhcmd1bWVudCBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiBmb2xkcyB0byBjcmVhdGUuClRoZSBgcmVwZWF0c2AgYXJndW1lbnQgc3BlY2lmaWVzIGlmIGFueSBzYW1wbGVzIHNob3VsZCBiZSByZXBlYXRlZCBhY3Jvc3MgZm9sZHMgLSBkZWZ1YWx0IGlzIGBGQUxTRWAKVGhlIGBzdHJhdGFgIGFyZ3VtZW50IHNwZWNpZmllcyBhIHZhcmlhYmxlIHRvIHN0cmF0aWZ5IHNhbXBsZXMgYWNyb3NzIGZvbGRzIChqdXN0IGxpa2UgaW4gYGluaXRpYWxfc3BsaXQoKWApLgoKQWdhaW4gYmVjYXVzZSB0aGVzZSBhcmUgY3JlYXRlZCBhdCByYW5kb20sIHdlIG5lZWQgdG8gdXNlIHRoZSBiYXNlIGBzZXQuc2VlZCgpYCBmdW5jdGlvbiBpbiBvcmRlciB0byBvYnRhaW4gdGhlIHNhbWUgcmVzdWx0cyBlYWNoIHRpbWUgd2Uga25pdCB0aGlzIGRvY3VtZW50LgoKYGBge3J9CnNldC5zZWVkKDEyMzQpCgp2Zm9sZF9wbSA8LXJzYW1wbGU6OnZmb2xkX2N2KGRhdGEgPSB0cmFpbl9wbSwgdiA9IDEwICkKCnZmb2xkX3BtCgoKdmZvbGRfcG0kc3BsaXRzJGAxYAp2Zm9sZF9wbSRzcGxpdHMkYDJgCmBgYAoKT25jZSB0aGUgZm9sZHMgYXJlIGNyZWF0ZWQgdGhleSBjYW4gYmUgdXNlZCB0byBldmFsdWF0ZSBwZWZvcm1hbmNlIGJ5IGZpdHRpbmcgdGhlIG1vZGVsIHRvIGVhY2ggb2YgdGhlIHJlc2FtcGxlcyB0aGF0IHdlIGNyZWF0ZWQ6CgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJjcm9zc192YWxpZGF0aW9uLnBuZyIpKQpgYGAKCgpXZSBjYW4gZml0IHRoZSBtb2RlbCB0byBvdXIgY3Jvc3MgdmFsaWRhdGlvbiBmb2xkcyB1c2luZyB0aGUgYGZpdF9yZXNhbXBsZXMoKWAgZnVuY3Rpb24gb2YgdGhlIGB0dW5lYCBwYWNrYWdlLCBieSBzcGVjaWZ5aW5nIG91ciB3b3JrZmxvdyBvYmplY3QgYW5kIHRoZSBjcm9zcyB2YWxpZGF0aW9uIGZvbGQgb2JqZWN0IHdlIGp1c3QgY3JlYXRlZC4gU2VlIFtoZXJlXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3R1bmUvcmVmZXJlbmNlL2ZpdF9yZXNhbXBsZXMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uCgpgYGB7cn0KY29udHJvbCA8LSBjb250cm9sX3Jlc2FtcGxlcyhzYXZlX3ByZWQgPSBUUlVFKQpyZXNhbXBsZV9maXQgPC10dW5lOjpmaXRfcmVzYW1wbGVzKFBNX3dmbG93LCB2Zm9sZF9wbSkKCmBgYAoKV2UgY2FuIG5vdyB0YWtlIGEgbG9vayBhdCB2YXJpb3VzIG1ldHJpY3Mgb2YgcGVyZm9ybWFuY2UgYmFzZWQgb24gdGhlIGZpdCBvZiBvdXIgMTAgY3Jvc3MgdmFsaWRhdGlvbiAicmVzYW1wbGVzIi4gVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYHNob3dfYmVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHR1bmVgIHBhY2thZ2UuCgpgYGB7cn0KdHVuZTo6c2hvd19iZXN0KHJlc2FtcGxlX2ZpdCwgbWV0cmljID0gInJtc2UiLCAicnNxIikKYGBgCgojIyMgVHVuaW5nCgpOb3cgbGV0J3MgdHJ5IHNvbWUgdHVuaW5nLgoKTGV0J3MgdGFrZSBhIGNsb3NlciBsb29rIGF0IGhvdyB0aGUgbW9uaXRvciB2YWx1ZXMgdmFyeSB3aXRoIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUuCgpgYGB7cn0KCnRyYWluX3BtICU+JSAKICBkcGx5cjo6c2VsZWN0KHZhbHVlLCBsb24sIGxhdCkgJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGMobG9uLCBsYXQpLCAKICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInByZWRpY3RvciIsIHZhbHVlc190byA9ICJsb2NfdmFsdWUiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9jX3ZhbHVlLCB2YWx1ZSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC4yKSArIAogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpICsgCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh+IHByZWRpY3Rvciwgc2NhbGVzID0gImZyZWVfeCIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGRvZXMgbm90IGFwcGVhciB0byBiZSBhIHNpbmdsZSBsaW5lYXIgcmVsYXRpb25zaGlwIGZvciBlaXRoZXIgb2YgdGhlc2UgcHJlZGljdG9ycy4gVGh1cyB3ZSBtaWdodCB3YW50IHRvIHRoaW5rIGFib3V0IHVzaW5nICBbc3BsaW5lc10oaHR0cHM6Ly93d3cubWF0aC51aC5lZHUvfmppbmdxaXUvbWF0aDQzNjQvc3BsaW5lLnBkZikgb3IgdGhpcyhodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vbnVtZXJpY2FsLWludGVycG9sYXRpb24tbmF0dXJhbC1jdWJpYy1zcGxpbmUtNTJjMTE1N2I5OGFjKSBvciBqdXN0IHRoaXMoaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby90dW5lL2FydGljbGVzL2dldHRpbmdfc3RhcnRlZC5odG1sKSBvciB0aGlzKGh0dHBzOi8vd3d3LnBzeWNoLm1jZ2lsbC5jYS9taXNjL2ZkYS9leC1iYXNpcy1iMS5odG1sKSB0byBtb2RlbCB0aGUgcmVsYXRpb25zaGlwIGluIG91ciB0cmFpbmluZyBkYXRhIG1vcmUgY2xvc2VseS4gRm9yIGV4YW1wbGUgZm9yIHRoZSBsYXRpdHVkZSBwbG90IChsZWZ0KSBpZiB3ZSBoYWQgMiBsaW5lcyBhbmQgb25lIGJyZWFrcG9pbnQgY2FsbGVkIGEga25vdCBhcm91bmQgNDAsIHdpdGggdGhlIGZpcnN0IGxpbmUgaGF2aW5nIGEgcG9zaXRpdmUgc2xvcGUgYW5kIHRoZSBzZWNvbmQgd2l0aCBhIG5lZ2F0aXZlIHNsb3BlIHRoaXMgd291bGQgZml0IHRoZSBkYXRhIG1vcmUgc2ltaWxhcmx5IHRvIHRoZSBibHVlIGxpbmUgc2hvd24gaW4gdGhlIGZpZ3VyZS4KCldlIGNhbiB0dW5lIGZvciB0aGUgbnVtYmVyIG9mIGtub3RzIGJ5IHVzaW5nIGEgc3RlcCBmdW5jdGlvbiBpbiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgY2FsbGVkIGBzdGVwX25zKClgIHdoZXJlIG5zIHN0YW5kcyBmb3IgbmF0dXJhbCBzcGxpbmVzLiBJbiBvcmRlciB0byB0dW5lIGZvciB0aGUgbnVtYmVyIG9mIGtub3RzIG9yIGRlZ3JlZXMgb2YgZnJlZWRvbSwgd2UgY2FuIHNldCB0aGUgYGRlZ19mcmVlYCBhcmd1bWVudCB0byBgdHVuZSgpYC4gVGhpcyBpcyBoZWxwZnVsLCBiZWN1YXNlIHdlIGFyZW4ndCBleGFjdGx5IHN1cmUgaG93IGNsb3NlbHkgd2Ugc2hvdWxkIGJlIGZvbGxvd2luZyB0aGUgcmVsYXRpb25zaGlwIHdpdGggdGhlIHZhbHVlIGFuZCBvdXIgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBkYXRhIGluIG91ciB0cmFpbmluZyBkYXRhIHRvIGFjaGlldmUgZ29vZCBhY2N1cmFjeSB5ZXQga2VlcCBvdXIgbW9kZWwgZ2VuZXJhbGl6YWJsZSBmb3Igb3RoZXIgZGF0YS4gCgpUaGlzIGlzIHdoZW4gb3VyIGNyb3NzIHZhbGlkYXRpb24gbWV0aG9kcyBiZWNvbWUgcmVhbGx5IGhhbmR5LiBXZSBjYW4gdGVzdCBvdXQgZGlmZmVyZW50IHZhbHVlcyBmb3IgdGhlIGBkZWdfZnJlZWAgYXJndW1lbnQgYW5kIHNlZSBob3cgb3VyIG1vZGVsIHBlcmZvcm1hbmNlIHZhcmllcyBhY3Jvc3Mgb3VyIHRyYWluaW5nIGZvbGRzIHRvIHRyeSB0byBmaW5kIHRoZSBvcHRpbWFsIHZhbHVlLgoKV2Ugd2lsbCB1cGRhdGUgb3VyIHJlY2lwZSB0byBhZGQgdGhlc2Ugc3RlcHMuIEl0IGlzIGEgZ29vZCBpZGVhIHRvIGRvIHRoaXMgZm9yIGluZGl2aWR1YWwgcHJlZGljdG9ycyBiZWNhdXNlIHlvdSBjYW4gbmFtZSBlYWNoIHdpdGggdGhlIGB0dW5lYCBhcmd1bWVudCBzbyB0aGF0IHlvdSBjYW4ga2VlcCB0cmFjayBvZiBpdCBsYXRlci4gV2UgY2FuIHNlZSB3aGF0IHdlIGludGVuZCB0byB0dW5lIHdpdGggdGhlIGBwYXJhbWV0ZXJzKClgIGZ1bmN0aW9uIG9mIHRoZSBgZGlhbHNgIHBhY2thZ2UuIAoKU2VlIFtoZXJlXSh0aGlzKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vdHVuZS9hcnRpY2xlcy9nZXR0aW5nX3N0YXJ0ZWQuaHRtbCkpIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGltcGxlbWVudGluZyB0aGlzIGluIHRpZHltb2RlbHMuCgpgYGB7cn0KCnNpbXBsZV9yZWMgJTw+JQogIHN0ZXBfbnMobG9uLCBkZWdfZnJlZSA9IHR1bmUoImxvbiBkZiIpKSAlPiUKICBzdGVwX25zKGxhdCwgIGRlZ19mcmVlID0gdHVuZSgibGF0IGRmIikpCiMgc2ltcGxlX3JlYyAlPD4lCiMgICBzdGVwX25zKGxhdCwgIGRlZ19mcmVlID0gdHVuZSgpKQojIHNpbXBsZV9yZWMKCnBtX3BhcmFtIDwtZGlhbHM6OnBhcmFtZXRlcnMoc2ltcGxlX3JlYykKcG1fcGFyYW0KYGBgCkdlbmVhcmxseSB5b3UgY291bGQgdXNlIHRoZSBgZ3JpZF8qKClgIGZ1bmN0aW9ucyBvZiB0aGUgYGRpYWxzYCBwYWNrYWdlIHRvIGNyZWF0ZSB0aGUgZGlmZmVyZW50IGNvbWJpbmF0aW9ucyBvZiBkZWdyZWVzIG9mIGZyZWVkb20gdG8gdGVzdCBmb3IgYm90aCB2YXJpYWJsZXMgdG8gb3B0aW1pemUgdGhlIG1vZGVsLiBJbiBvdXIgY2FzZSB3ZSBjYW4gdmlzYWJseSBzZWUgdGhhdCBpZiB3ZSBhZGQgbW9yZSB0aGFuIHNheSA0IG9yIDUgZGVncmVlcyBvZiBmcmVlZG9tIHdlIHdpbGwgbGlrZWx5IG92ZXJmaXQgdGhlIGRhdGEuIFNvIGluc3RlYWQgb2YgdXNpbmcgdGhlc2UgZnVuY3Rpb25zIHdlIHdpbGwgY3JlYXRlIG91ciBvd24gZ3JpZCB1c2luZyB0aGUgYmFzZSBgc2VxKClgIGFuZCBgZXhwYW5kLmdyaWQoKWAgZnVuY3Rpb25zLgoKYGBge3J9CiNhbiBleGFtcGxlIG9mIHdoYXQgeW91IGNvdWxkIGRvOgojc3BsaW5lX2dyaWQgPC1kaWFsczo6Z3JpZF9yZWd1bGFyKHBtX3BhcmFtLCBsZXZlbHMgPSAzKQpkZl92YWxzIDwtIHNlcSgxLCA1LCBieSA9IDIpCnNwbGluZV9ncmlkIDwtIGV4cGFuZC5ncmlkKGBsb24gZGZgID0gZGZfdmFscywgYGxhdCBkZmAgPSBkZl92YWxzKQpzcGxpbmVfZ3JpZApgYGAKCgpOb3cgd2Ugd2lsbCB0dW5lIHRoaXMgaHlwZXItcGFyYW1ldGVyIChkZWdyZWVzIG9mIGZyZWVkb20pIGZvciBib3RoIHRoZSBgbGF0YCBhbmQgYGxvbmAgdmFyaWFibGVzIHVzaW5nIG91ciBjcm9zcyB2YWxpZGF0aW9uIGZvbGRzLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgdHVuZV9ncmlkKClgIGZ1bmN0aW9uIG9mIHRoZSBgdHVuZWAgcGFja2FnZS4KCmBgYHtyfQoKZGZfdHVuaW5nIDwtbG1fUE1fbW9kZWwgJT4lIAogIHR1bmU6OnR1bmVfZ3JpZChzaW1wbGVfcmVjLCByZXNhbXBsZXMgPXZmb2xkX3BtLCAKICAgICAgICAgICAgICAgICAgZ3JpZCA9IHNwbGluZV9ncmlkKQoKI2RmX3R1bmluZyA8LVBNX3dmbG93ICU+JSB0dW5lOjp0dW5lX2dyaWQocmVzYW1wbGVzID12Zm9sZF9wbSwgCiAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWQgPSBzcGxpbmVfZ3JpZCwgCiAgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbV9zZXQgPXBtX3BhcmFtKQoKZGZfdHVuaW5nCmBgYAoKCgpgYGB7cn0KCmRmX3R1bmluZyAlPiUKICBjb2xsZWN0X21ldHJpY3MoKQoKY29sbGVjdF9tZXRyaWNzKGRmX3R1bmluZykKc2hvd19iZXN0KGRmX3R1bmluZywgbWV0cmljID0gInJtc2UiLCBuID0xKQpgYGAKCgojIyMgTGluZWFyIFJlZ3Jlc3Npb24gTW9kZWwgd2l0aCBQQ0EKCmBgYHtyfQpsbV9QQ0FfcmVjIDwtcmVjaXBlKHRyYWluX3BtKSAlPiUKICAgIHVwZGF0ZV9yb2xlKGV2ZXJ5dGhpbmcoKSwgbmV3X3JvbGUgPSAicHJlZGljdG9yIiklPiUKICAgIHVwZGF0ZV9yb2xlKHZhbHVlLCBuZXdfcm9sZSA9ICJvdXRjb21lIiklPiUKICAgIHVwZGF0ZV9yb2xlKGlkLCBuZXdfcm9sZSA9ICJpZCB2YXJpYWJsZSIpICU+JQogICAgdXBkYXRlX3JvbGUoImZpcHMiLCBuZXdfcm9sZSA9ICJjb3VudHkgaWQiKSAlPiUKICAgIHN0ZXBfZHVtbXkoc3RhdGUsIGNvdW50eSwgY2l0eSwgemN0YSkgJT4lCiAgICBzdGVwX3BjYShhbGxfcHJlZGljdG9ycygpKSAKYGBgCgpXZSB3dGlsbCB3YW50IHRvIHVzZSB0aGUgYGxtYCBwYWNrYWdlIGZvciBvdXIgcmVncmVzc2lvbiBzbyB3ZSBjYW4gdXNlIHRoZSBzYW1lIG1vZGVsIG9iamVjdDoKYGBge3J9CmxtX1BNX21vZGVsCmBgYAoKV2UgY2FuIGNyZWF0ZSBhbm90aGVyIHdvcmtmbG93OgpgYGB7cn0KcGNhX3dmbG93IDwtd29ya2Zsb3dzOjp3b3JrZmxvdygpICU+JQogICAgICAgICAgIHdvcmtmbG93czo6YWRkX3JlY2lwZShsbV9QQ0FfcmVjKSAlPiUKICAgICAgICAgICB3b3JrZmxvd3M6OmFkZF9tb2RlbChsbV9QTV9tb2RlbCkKcGNhX3dmbG93CmBgYAoKRml0IHRoZSBjcm9zcyB2YWxpZGF0aW9uIHNhbXBsZXM6CgpgYGB7cn0KcmVzYW1wbGVfcGNhX2ZpdCA8LXR1bmU6OmZpdF9yZXNhbXBsZXMocGNhX3dmbG93LCB2Zm9sZF9wbSkKYGBgCgoKTG9vayBhdCB0aGUgcGVyZm9ybWFuY2U6CmBgYHtyfQpjb2xsZWN0X21ldHJpY3MocmVzYW1wbGVfcGNhX2ZpdCkKYGBgCgpBbmQgd2UgY2FuIGNvbXBhcmUgdGhpcyB3aXRoIG91ciBwcmV2aW91cyBwZXJmb3JtYW5jZToKCmBgYHtyfQpjb2xsZWN0X21ldHJpY3MocmVzYW1wbGVfZml0KQpgYGAKCgpMZXQncyByZXZpZXcgZXZlcnl0aGluZzoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwidGlkeW1vZGVsc19lY29zeXN0ZW0ucG5nIikpCmBgYAoKCgoKPiBjaGVja19uZXdfdmFsdWVzOiBUaGlzIGNoZWNrIHdpbGwgYnJlYWsgdGhlIGJha2UgZnVuY3Rpb24gaWYgYW55IG9mIHRoZSBjaGVja2VkIGNvbHVtbnMgZG9lcyBjb250YWluIHZhbHVlcyBpdCBkaWQKbm90IGNvbnRhaW4gd2hlbiBwcmVwIHdhcyBjYWxsZWQgb24gdGhlIHJlY2lwZS4gSWYgdGhlIGNoZWNrIHBhc3Nlcywgbm90aGluZyBpcyBjaGFuZ2VkIHRvIHRoZSBkYXRhCgo+IGNoZWNrX3JhbmdlIGNyZWF0ZXMgYSBzcGVjaWZpY2F0aW9uIG9mIGEgcmVjaXBlIGNoZWNrIHRoYXQgd2lsbCBjaGVjayBpZiB0aGUgcmFuZ2Ugb2YgYSBudW1lcmljCnZhcmlhYmxlIGNoYW5nZWQgaW4gdGhlIG5ldyBkYXRhLgoKCgpbcGFyYW1ldGVyIHZzIGh5cGVycGFyYW1ldGVyXShodHRwczovL3d3dy5kYXRhY2FtcC5jb20vY29tbXVuaXR5L3R1dG9yaWFscy9wYXJhbWV0ZXItb3B0aW1pemF0aW9uLW1hY2hpbmUtbGVhcm5pbmctbW9kZWxzKXt0YXJnZXQ9Il9ibGFuayJ9CgoKCnByZXBwZXIgZm9yIGNyb3NzIHZhbGlkYXRpb24/CgoKCgoKCmdyZWF0IGJsb2cgYWJvdXQgY3Jvc3MgdmFsaWRhdGlvbiBldGMgaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3RyYWluLXRlc3Qtc3BsaXQtYW5kLWNyb3NzLXZhbGlkYXRpb24taW4tcHl0aG9uLTgwYjYxYmVjYTRiNgoKIyMgRGF0YSBWaXN1YWxpemF0aW9uCgojIyBTdW1tYXJ5CgpXZSBoYXZlIGV2YWx1YXRlZCBhdmVyYWdlIGNvbnN1bXB0aW9uIGVzdGltYXRlcyBvZiAxNSBkaWV0YXJ5IGZhY3RvcnMgd2l0aCBwcm9iYWJseSBub24tY29tbXVuaWNhYmxlIGRpc2Vhc2UgKE5DRCkgcmlzayBmcm9tIDE5NSBkaWZmZXJlbnQgY291bnRyaWVzIGFyb3VuZCB0aGUgd29ybGQuIFRvIGRvIHNvIHdlIGltcG9ydGVkIGRhdGEgZnJvbSBhIFBERiB1c2luZyB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLCBhcyB3ZWxsIGFzIGRhdGEgZnJvbSB0d28gQ1NWIGZpbGVzIHVzaW5nIHJlYWRyLiBXZSB1c2VkIGB0aWR5dmVyc2VgIHBhY2thZ2VzIHN1Y2ggYXMgYGRwbHlyYCwgYHN0cmluZ3JgLCBhbmQgYHRpZHlgIHRvIGNsZWFuIGFuZCBqb2luIHRoZSBkYXRhIGZyb20gdGhlIFBERiB3aXRoIHRoZSBDU1YgZmlsZXMuIAoKV2UgbGVhcm5lZCB0aGF0IFJlZ3Jlc3Npb24gaXMgYSBwb3dlcmZ1bCBhbmQgZmxleGlibGUgc3RhdGlzdGljYWwgdG9vbCB0aGF0IHNpbXBsaWZpZXMgb3IgZXN0aW1hdGVzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIHVzaW5nIGEgbWF0aGVtYXRpY2FsIG1vZGVsLiBXZSBsZWFybmVkIGFib3V0IHRoZSB1dGlsaXR5IG9mIHRoZSByZWdyZXNzaW9uIHRvIGNvbXBhcmUgZ3JvdXBzLCBsb29rIGZvciBhc3NvY2lhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMsIGFuZCB0byBwcmVkaWN0IG91dGNvbWVzIGJhc2VkIG9uIG11bHRpcGxlIHByZWRpY3RvciBvciBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIFdlIHRoZW4gY29tcGFyZWQgdGhpcyB0byBvdGhlciBwb3B1bGFyIHRlc3RzIGxpa2UgdGhlICR0JC10ZXN0IGFuZCB0aGUgQU5PVkEuIFdlIGxlYXJuZWQgdGhhdCB0aGVzZSB0ZXN0cyBhcmUgYWN0dWFsbHkgZXF1aXZhbGVudCB0byBzcGVjaWFsaXplZCB0eXBlcyBvZiByZWdyZXNzaW9ucy4KCk91ciBzdGF0aXN0aWNhbCBhbmFseXNpcyBmb2N1c2VkIG9uIGV2YWx1YXRpbmcgZGlmZmVyZW5jZXMgaW4gdGhlIGNvbnN1bXB0aW9uIG9mIHJlZCBtZWF0IGFyb3VuZCB0aGUgd29ybGQgYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyBhbmQgYWNyb3NzIGRpZmZlcmVudCBhZ2UgZ3JvdXBzLiBGaXJzdCB3ZSBsb29rZWQgYXQgdGhlIGFzc3VtcHRpb25zIG9mIFskdCQtdGVzdHNdKGh0dHBzOi8vc3RhdHRyZWsuY29tL3N0YXRpc3RpY3MvZGljdGlvbmFyeS5hc3B4P2RlZmluaXRpb249dHdvLXNhbXBsZSUyMCR0JC10ZXN0KXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCByZWdyZXNzaW9ucywgYW5kIGRldGVybWluZWQgdGhhdCB0aGUgcmVsYXRpdmUgcGVyY2VudGFnZSBkYXRhIG9mIHJlZCBtZWF0IGNvbnN1bXB0aW9uIHRvIHRoZSBvcHRpbWFsIGd1aWRlbGluZSBzdWdnZXN0ZWQgYW1vdW50IHdhcyByaWdodCBza2V3ZWQuIFdlIGxlYXJuZWQgdGhhdCB3ZSBjb3VsZCB0cmFuc2Zvcm0gdGhlIGRhdGEgYnkgdGFraW5nIHRoZSBsb2cgb2YgdGhlc2UgdmFsdWVzIHRvIGFjaGlldmUgbW9yZSBub3JtYWxseSBkaXN0cmlidXRlZCBkYXRhLiBUbyBjb21wYXJlIG1hbGVzIGFuZCBmZW1hbGVzIHdlIHVzZWQgYSAkdCQtdGVzdCBhbmQgbGVhcm5lZCB0aGF0IGEgJHQkLXRlc3QgaXMgYSBzcGVjaWFsaXplZCBmb3JtIG9mIGEgbGluZWFyIHJlZ3Jlc3Npb24uIFRvIGNvbXBhcmUgdGhlIDE1IGRpZmZlcmVudCBhZ2UgZ3JvdXBzIHdlIHVzZWQgYW4gQU5PVkEgYW5kIGxlYXJuZWQgdGhhdCB0aGUgQU5PVkEgaXMgYWxzbyBhIHNwZWNpYWxpemVkIGZvcm0gb2YgbGluZWFyIHJlZ3Jlc3Npb24uIFdlIGV4YW1pbmVkIGhvdyB3ZSBvYnRhaW5lZCB0aGUgc2FtZSByZXN1bHRzIHVzaW5nIGVpdGhlciBzdGF0aXN0aWNhbCB0ZXN0LiBUaGlzIHdhcyBhbHNvIHRoZSBjYXNlIGlmIHdlIGxvb2tlZCBhdCB0aGUgZWZmZWN0IG9mIGdlbmRlciBhbmQgY29udHJvbGxlZCBmb3IgdGhlIHBhaXJlZCBjb3VudHJ5IHN0cnVjdHVyZSBpbiB0aGUgZGF0YSBieSBlaXRoZXIgaW5jbHVkaW5nIGBsb2NhdGlvbl9uYW1lYCBpbiB0aGUgbW9kZWwgYXMgYW5vdGhlciB0ZXJtIG9yIGJ5IHVzaW5nIGEgbWl4ZWQgZWZmZWN0cyBtb2RlbCB0byBjb250cm9sIGZvciB0aGlzIHN0cnVjdHVyZSBhcyBhIHJhbmRvbSBlZmZlY3QgYnV0IG5vdCBzcGVjaWZpY2FsbHkgdGVzdCBmb3IgdGhlIGluZmx1ZW5jZSBvZiBgbG9jYXRpb25fbmFtZWAgb24gcmVkIG1lYXQgY29uc3VtcHRpb24gZXN0aW1hdGVzLiBXZSBsZWFybmVkIHRoYXQgZml4ZWQgZWZmZWN0cyBhcmUgdGhvc2UgdGhhdCB3ZSB3aXNoIHRvIGV2YWx1YXRlLCB3aGlsZSByYW5kb20gZWZmZWN0cyBhcmUgdGhvc2UgdGhhdCBtYXkgaW5mbHVlbmNlIHRoZSByZWxhdGlvbnNoaXBzIG9mIG91ciB2YXJpYWJsZXMgb2YgaW50ZXJlc3QgYnV0IHRoYXQgd2UgZG8gbm90IHdpc2ggdG8gYWN0aXZlbHkgZXZhbHVhdGUuIFVzaW5nIHRoZXNlIHRlc3RzIGFuZCBtb2RlbHMsIHdlIGRldGVybWluZWQgdGhhdCBtYWxlcyBjb25zdW1lIG1vcmUgcmVkIG1lYXQgdGhhbiB3b21lbiBvbiBhdmVyYWdlIGFyb3VuZCB0aGUgd29ybGQuIAoKT3VyIEFOT1ZBIGFuYWx5c2lzIG9mIGFnZSBkZXRlcm1pbmVkIHRoYXQgaW5kZWVkIHRoZXJlIGF0IGxlYXN0IG9uZSBhZ2UgZ3JvdXAgY29uc3VtZWQgYSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBhbW91bnQgb2YgcmVkIG1lYXQgY29tcGFyZWQgdG8gdGhlIG90aGVyIGFnZSBncm91cHMsIGFuZCB0aGlzIHdhcyBzdGlsbCB0aGUgY2FzZSB3aGVuIHdlIGNvbnRyb2xsZWQgYGxvY2F0aW9uX25hbWVgLiBIb3dldmVyLCB3ZSBsZWFybmVkIHRoYXQgd2UgY291bGQgdGhhdCB0aGUgQU5PVkEgZG9lcyBub3QgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCBhZ2UgZ3JvdXBzIGFyZSBkaWZmZXJlbnQuIFdlIGxlYXJuZWQgaG93IHRoZSByZWdyZXNzaW9uIGhvd2V2ZXIgY291bGQgcHJvdmlkZSBzb21lIGNvbXBhcmlzb25zIG9mIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIHJlbGF0aXZlIHRvIHRoZSByZWZlcmVuY2UgYWdlIGdyb3VwLiBGdXJ0aGVybW9yZSwgb3VyIGRhdGEgdmlzdWFsaXphdGlvbnMgYWxsb3dlZCB1cyB0byBkZXRlcm1pbmUgdGhhdCBpbiBnZW5lcmFsIHJlZCBtZXQgY29uc3VtcHRpb24gYXBwZWFycyB0byBiZSBoaWdoZXIgaW4gdGhlIHlvdW5nZXIgYWdlIGdyb3VwcyByZWxhdGl2ZSB0byB0aGUgb2xkZXIgYWdlIGdyb3Vwcy4gCgpGaW5hbGx5LCB3ZSBhbHNvIGxvb2tlZCBhdCBkaWZmZXJlbmNlcyBpbiByZWQgbWVhdCBjb25zdW1wdGlvbiBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgY291bnRyaWVzIGFuZCBzYXcgaW4gb3VyIEFOT1ZBIGFuYWx5c2lzIGFuZCBvdXIgcmVncmVzc2lvbiBhbmFseXNpcyB0aGF0IHRoZXJlIHdlcmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMuIFdlIHdlcmUgYWJsZSB0byB1c2UgYSByZWdyZXNzaW9uIHRoYXQgaW5jbHVkZWQgYHNleGAsIGBhZ2VfZ3JvdXBfbmFtZWAsIGFuZCBgbG9jYXRpb25fbmFtZWAgdG8gZXZhbHVhdGUgdGhlIGluZmx1ZW5jZSBvZiBlYWNoIG9mIHRoZSB0aHJlZSBkZW1vZ3JhcGhpYyBmYWN0b3JzIG9uIGNvbnN1bXB0aW9uIHdoaWxlIGNvbnRyb2xsaW5nIG9yIGFjY291bnRpbmcgZm9yIHRoZSBvdGhlciB0d28uIE91ciByZXN1bHRzIGRlbW9uc3RyYXRlZCB0aGF0IGFsbCB0aHJlZSBpbmZsdWVuY2VkIG9yIHdlcmUgYXNzb2NpYXRlZCB3aXRoIHJlZCBtZWF0IGNvbnN1bXB0aW9uLgoKSW4gcHJlZm9ybWluZyBvdXIgc3RhdGlzdGljYWwgYW5hbHlzZXMgd2UgbGVhcm5lZCBhYm91dCB0aGUgYXNzdW1wdGlvbnMgb2YgdGhlICR0JC10ZXN0LCB0aGUgcmVncmVzc2lvbiwgYW5kIHRoZSBBTk9WQS4gV2UgYWxzbyBsZWFybmVkIGFib3V0IGltcG9ydGFudCBtZXRob2RzIHRvIHRlc3RzIHRoZXNlIGFzc3VtcHRpb25zLgoKIyMjIyAkdCQtdGVzdCBhc3N1bXB0aW9uczoKCjEpIE5vcm1hbGl0eSBvZiB0aGUgZGF0YSBmb3IgYm90aCBncm91cHMgKHRoaXMgaXMgbm90IGFzIG11Y2ggb2YgYW4gaXNzdWUgaWYgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaXMgcmVsYXRpdmVseSBsYXJnZSB0b3RhbCBuPjMwIC0gY2FuIGV2YWx1YXRlIGJ5IHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24gYW5kIGJ5IGNyZWF0aW5nIFtRLVEgcGxvdHNdKFtRLVEgUGxvdHNdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9hZHZhbmNlZF9ncmFwaHMvcS1xX3Bsb3RzLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0pKQoyKSBFcXVhbCB2YXJpYW5jZSBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzIChtYWtlIHN1cmUgeW91IGRvIHRoZSBjb3JyZWN0IHRlc3QgaWYgdGhlIGRhdGEgaXMgbm90IG5vcm1hbCkKMykgQmFsYW5jZWQgc2FtcGxlIHNpemVzIG9mIHRoZSB0d28gZ3JvdXBzCjQpIEluZGVwZW5kZW50IG9ic2VydmF0aW9ucyAob3IgaW5kZXBlbmRlbnQgcGFpcmVkIG9ic2VydmF0aW9ucykKCldlIGNhbiBldmFsdWF0ZSBpZiBvdXIgZGF0YSBpcyBbbm9ybWFsbHkgZGlzdHJpYnV0ZWRdKGh0dHBzOi8vd3d3LnBoeXNpb2xvZ3kub3JnL2RvaS9mdWxsLzEwLjExNTIvYWR2YW4uMDAwNjQuMjAxNyl7dGFyZ2V0PSJfYmxhbmsifSBieSBwbG90dGluZyB0aGUgZGlzdHJpYnV0aW9uIGFuZCBieSBjcmVhdGluZyBbUS1RIHBsb3RzXShbUS1RIFBsb3RzXShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvYWR2YW5jZWRfZ3JhcGhzL3EtcV9wbG90cy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgZGF0YSB0byB0aGUgdGhlb3JldGljYWwgW25vcm1hbCBkaXN0cmlidXRpb25dKGh0dHBzOi8vd3d3LnBoeXNpb2xvZ3kub3JnL2RvaS9mdWxsLzEwLjExNTIvYWR2YW4uMDAwNjQuMjAxNyl7dGFyZ2V0PSJfYmxhbmsifS4KCjx1PklmIG91ciBkYXRhIGlzIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCwgd2UgY2FuIGNvbnNpZGVyIHRoZXNlIG9wdGlvbnM6PC91PgoKMSkgV2UgY2FuIHN0aWxsIHBlcmZvcm0gYSAkdCQtdGVzdCBpZiBvdXIgbiBpcyBsYXJnZQoyKSBXZSBjYW4gdHJhbnNmb3JtIHRoZSBkYXRhIGJlZm9yZSBwZXJmb3JtaW5nIGEgJHQkLXRlc3QKMykgV2UgY2FuIHVzZSBhIG5vbnBhcmFtZXRyaWMgdGVzdCAoV2lsY294b24gc2lnbmVkIHJhbmsgdGVzdCwgdGhlIFdpbGNveG9uIHJhbmsgc3VtIHRlc3QsIGFuZCB0aGUgVHdvLXNhbXBsZSBLb2xtb2dvcm92LVNtaXJub3YgKEtTKSB0ZXN0KQo0KSBXZSBjYW4gcGVyZm9ybSBhICR0JC10ZXN0IHdpdGggcmVzYW1wbGluZyBtZXRob2RzICh3aGljaCBzaG91bGQgYmUgZXNwZWNpYWxseSBjb25zaWRlcmVkIHdoZW4gdGhlIGdyb3VwcyBhcmUgaW1iYWxhbmNlZCkKClNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLXJ1cmFsLWFuZC11cmJhbi1vYmVzaXR5KXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIG9uICR0JC10ZXN0IGFzc3VtcHRpb25zLgoKV2UgbGVhcm5lZCB0aGF0IHdlIGNhbiB0ZXN0IGlmIDIgZ3JvdXBzIGhhdmUgZXF1YWwgdmFyaWFuY2UgdXNpbmc6ICAKMSkgdGhlIEYgdGVzdCB3aXRoIGB2YXIudGVzdCgpYCAgCjIpIE1vb2QncyB0ZXN0IHVzaW5nIFtgbW9vZC50ZXN0KClgXShodHRwczovL2ZpbGVzLmVyaWMuZWQuZ292L2Z1bGx0ZXh0L0VEMDY1NTU5LnBkZikgKHVzZSBpZiB0aGUgZGF0YSBpcyBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQpICAKCiMjIyMgTGluZWFyIHJlZ3Jlc3Npb24gYXNzdW1wdGlvbnM6CgpMIChsaW5lYXIpIC0gVGhlcmUgaXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcy4gIApJIChpbmRlcGVuZGVudCkgLSBUaGUgc2FtcGxlcyBhcmUgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlci4gIApOIChub3JtYWwpIC0gVGhlIHJlc2lkdWFscyBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuICAKRSAoZXF1YWwgdmFyaWFuY2VzKSAtIFRoZSB2YXJpYW5jZSBvZiB0aGUgcmVzaWR1YWxzIG9mIHRoZSBncm91cHMgaXMgc2ltaWxhci4gICAKSXQgaXMgYWxzbyBpbXBvcnRhbnQgdGhhdCBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBub3QgY29ycmVsYXRlZCB3aXRoIG9uZSBhbm90aGVyLiAgCgojIyMjIEFOT1ZBIGFzc3VtcHRpb25zOgoKMSkgTm9ybWFsaXR5IG9mIHRoZSBkYXRhIGZvciBhbGwgdGVzdGVkIGdyb3VwcyAobGVzcyBvZiBhbiBpc3N1ZSBpZiB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyByZWxhdGl2ZWx5IGxhcmdlIHRvdGFsIG4+MzApIAoyKSBFcXVhbCB2YXJpYW5jZSBiZXR3ZWVuIHRoZSBncm91cHMgLSBha2EgSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2UgKG1ha2Ugc3VyZSB5b3UgZG8gdGhlIGNvcnJlY3QgdGVzdCBpZiB0aGUgZGF0YSBpcyBub3Qgbm9ybWFsKSAKMykgQmFsYW5jZWQgc2FtcGxlIHNpemVzIG9mIHRoZSBncm91cHMgCjQpIEluZGVwZW5kZW50IG9ic2VydmF0aW9ucyAob3IgaW5kZXBlbmRlbnQgcGFpcmVkIG9ic2VydmF0aW9ucykgCgpXZSBsZWFybmVkIGFib3V0IHRocmVlIHRlc3RzIGZvciBleGFtaW5pbmcgdGhlIGVxdWFsaXR5IG9mIHZhcmlhbmNlIG9mIDMgb3IgbW9yZSBncm91cHM6CjEpIFtCYXJ0bGV0dCdzIHRlc3RdKGh0dHBzOi8vd3d3Lml0bC5uaXN0Lmdvdi9kaXY4OTgvaGFuZGJvb2svZWRhL3NlY3Rpb24zL2VkYTM1Ny5odG0pe3RhcmdldD0iX2JsYW5rIn0gKHdvcmtzIHdlbGwgaWYgdGhlIGRhdGEgYXBwZWFycyB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZCkgCjIpIFtGbGlnbmVyLUtpbGxlZW5dKGh0dHA6Ly93aWtpLnN0YXQudWNsYS5lZHUvc29jci9pbmRleC5waHAvQVBfU3RhdGlzdGljc19DdXJyaWN1bHVtXzIwMDdfTm9uUGFyYW1fVmFySW5kZXApe3RhcmdldD0iX2JsYW5rIn0gdGVzdCBpcyBub25wYXJhbWV0cmljIGFuZCBkb2VzIG5vdCBhc3N1bWUgbm9ybWFsaXR5IAozKSBbTGV2ZW5lJ3MgdGVzdF0oaHR0cHM6Ly93d3cuaXRsLm5pc3QuZ292L2Rpdjg5OC9oYW5kYm9vay9lZGEvc2VjdGlvbjMvZWRhMzVhLmh0bSl7dGFyZ2V0PSJfYmxhbmsifSwgaXMgbW9yZSByb2J1c3QgdG8gdmlvbGF0aW9ucyBvZiBub3JtYWxpdHkgdGhhbiB0aGUgQmFydGxldHQncyB0ZXN0LCBidXQgbm90IGFzIHJvYnVzdCBhcyB0aGUgRmxpZ25lci0gS2lsbGVlbiB0ZXN0IAoKClVzaW5nIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB3ZSB3ZXJlIGFibGUgdG8gdmlzdWFsaXplIHRyZW5kcyBpbiB0aGUgZGF0YSBhbmQgdG8gY29tcGFyZSBjb25zdW1wdGlvbiBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMgaW4gdGhlIFVTIHdpdGggdGhhdCBvZiB0aGUgb3RoZXIgY291bnRyaWVzLgpXZSBzZWUgdGhhdCB0aGUgcG9wdWxhdGlvbnMgaW4gbWFueSBjb3VudHJpZXMgYXJlIG92ZXItY29uc3VtaW5nIGZvb2RzIHRoYXQgYXJlIGFzc29jaWF0ZWQgd2l0aCBoZWFsdGggcmlzayB3aGVuIG92ZXItY29uc3VtZWQuIEluIHBhcnRpY3VsYXIgcHJvY2Vzc2VkIG1lYXQgYW5kIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgYXBwZWFyIHRvIGJlIHRoZSBtb3N0IG92ZXIgY29uc3VtZWQuIEltcG9ydGFudGx5IGJvdGggb2YgdGhlc2UgYXBwZWFyIHRvIGJlIGNvbnN1bWVkIGF0IGhpZ2hlciBxdWFudGl0aWVzIGJ5IG1hbGVzIGFuZCB5b3VuZ2VyIGFkdWx0cy4gUGVvcGxlIGluIHRoZSBVUyAgYXBwZWFyIHRvIGNvbnN1bWUgbGVzcyBzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIHRoYW4gb3RoZXIgY291bnRyaWVzLCBob3dldmVyLCBwZW9wbGUgYXJlIHN0aWxsIG92ZXItY29uc3VtaW5nLiBQcm9jZXNzZWQgbWVhdCBob3dldmVyIGFwcGVhcnMgdG8gYmUgZXNwZWNpYWxseSBiYWQgaW4gdGhlIFVTLiBJbiB0ZXJtcyBvZiBmb29kIHRoYXQgbmVlZCB0byBiZSBjb25zdW1lZCBpbiBhZGVxdWF0ZSBhbW91bnRzIHRvIG92ZXJjb21lIGhlYWx0aCByaXNrLCBuZWFybHkgYWxsIGNvdW50cmllcyBmb3IgYWxsIGZhY3RvcnMgYXJlIG5vdCByZWFjaGluZyBndWlkZWxpbmUgbGV2ZWxzLiBIb3dldmVyLCB0aGVyZSBhcmUgc29tZSBjb3VudHJpZXMgY29uc3VtaW5nIG1vcmUgdGhhbiBhZGVxdWF0ZSBhbW91bnRzIG9mIGxlZ3VtZXMsIHZlZ2V0YWJsZXMsIGZydWl0cyBhbmQgZmliZXIuIFBlb3BsZSBpbiB0aGUgVVMgYXBwZWFyIHRvIGVhdCBtb3JlIG1pbGsgcHJvZHVjdHMgYW5kIGNvbnN1bWUgbW9yZSBvbWVnYS0zIGZhdHR5IGFjaWQgYW5kIGNhbGNpdW0gcmljaCBmb29kcyB0aGFuIG90aGVyIGNvdW50cmllcy4gQWxsIGNvdW50cmllcyBpbmNsdWRpbmcgdGhlIFVTIGNvbnN1bWUgdmVyeSBsb3cgbGV2ZWxzIG9mIHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcy4gVGhlc2UgW3BvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUG9seXVuc2F0dXJhdGVkX2ZhdCkgYXJlIGFidW5kYW50IGluIHNlZWRzLCBudXRzLCBhdm9jYWRvcywgYXMgd2VsbCBhcyBmaXNoLiBMaWtlbHkgdGhlIGxvdyBsZXZlbCBvZiBjb25zdW1wdGlvbiBvZiBudXRzIGFuZCBzZWVkcyBjb250cmlidXRlcyB0byB0aGVzZSBsb3cgcG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWQgZXN0aW1hdGVzLiBUaGUgc3VwcGxlbWVudGFyeSB0YWJsZSBpbmNsdWRlZCBpbiB0aGUgYXJ0aWNsZSBzdWdnZXN0cyB0aGF0IHBvb3IgY29uc3VtcHRpb24gb2YgcG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzIGlzIGFzc29jaWF0ZWQgd2l0aCBpc2NoZW1pYyBoZWFydCBkaXNlYXNlLiBUaGUgYXJ0aWNsZSB0YWtlcyB0aGlzIGRhdGEgZnVydGhlciB0byBldmFsdWF0ZSB0aGUgYXNzb2NpYXRpb24gb2YgY29uc3VtcHRpb24gbGV2ZWxzIG9mIHRoZXNlIGZvb2RzIHdpdGggbW9ydGFsaXR5LgoKQW5hbHlzZXMgbGlrZSB0aGUgb25lIGluIG91ciBjYXNlIHN0dWR5IGFyZSBpbXBvcnRhbnQgZm9yIGRlZmluaW5nIHdoaWNoIGdyb3VwcyBjb3VsZCBiZW5lZml0IHRoZSBtb3N0IGZyb20gaW50ZXJ2ZW50aW9ucywgZWR1Y2F0aW9uLCBhbmQgcG9saWN5IGNoYW5nZXMgd2hlbiBhdHRlbXB0aW5nIHRvIG1pdGlnYXRlIHB1YmxpYyBoZWFsdGggY2hhbGxlbmdlcy4gWW91IGNhbiBzZWUgaW4gdGhlIFthcnRpY2xlXShodHRwczovL3d3dy50aGVsYW5jZXQuY29tL2FjdGlvbi9zaG93UGRmP3BpaT1TMDE0MC02NzM2JTI4MTklMjkzMDA0MS04KXt0YXJnZXQ9Il9ibGFuayJ9IGhvd2V2ZXIgdGhhdCBtYW55IGFkZGl0aW9uYWwgY29uc2lkZXJhdGlvbnMgd291bGQgYmUgaW52b2x2ZWQgdG8gcGVyZm9ybSBhIG1vcmUgdGhvcm91Z2ggYW5hbHlzaXMgdG8gYWRlcXVhdGVseSB1bmRlcnN0YW5kIHRoZSBkYXRhIGVub3VnaCB0byByZWNvbW1lbmQgcG9saWN5IGNoYW5nZXMuCgoKIyMjIFN1Z2dlc3RlZCBIb21ld29yawoKU3R1ZGVudHMgY2FuIGV2YWx1YXRlIGNvbnN1bXB0aW9uIGVzdGltYXRlcyBvZiBhbm90aGVyIGRpZXRhcnkgZmFjdG9yIGJlc2lkZXMgcmVkIG1lYXQuCgojIyMgSGVscGZ1bCBMaW5rcwoKcmV2aWV3IG9mIFt0aWR5bW9kZWxzXShodHRwczovL3J2aWV3cy5yc3R1ZGlvLmNvbS8yMDE5LzA2LzE5L2EtZ2VudGxlLWludHJvLXRvLXRpZHltb2RlbHMvKXt0YXJnZXQ9Il9ibGFuayJ9IAoKZ3VpZGUgZm9yIFtwcmVwcm9jZXNzaW5nIHdpdGggcmVjaXBlc10oaHR0cDovL3d3dy5yZWJlY2NhYmFydGVyLmNvbS9ibG9nLzIwMTktMDYtMDZfcHJlX3Byb2Nlc3NpbmcvKQoKW2d1aWRlXShodHRwczovL2JyaWF0dGUuZ2l0aHViLmlvL2dnY29yci8pIGZvciB1c2luZyBHR2FsbHkgdG8gY3JlYXRlIGNvcnJlbGF0aW9uIHBsb3RzCltndWlkZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy9ibG9nLzIwMTgvMTEvcGFyc25pcC0wLTAtMS8pIGZvciB1c2luZyBwYXJzbmlwIHRvIHRyeSBkaWZmZXJlbnQgYWxnb3JpdGhtcyBvciBlbmdpbmVzCltyZWNpcGUgZnVuY3Rpb25zXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JlY2lwZXMvcmVmZXJlbmNlL2luZGV4Lmh0bWwpCgo8dT5UZXJtcyBhbmQgY29uY2VwdHMgY292ZXJlZDo8L3U+ICAKCltUaWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1JTdHVkaW8gY2hlYXRzaGVldHNdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltJbmZlcmVuY2VdKGh0dHBzOi8vd3d3LmJyaXRhbm5pY2EuY29tL3NjaWVuY2UvaW5mZXJlbmNlLXN0YXRpc3RpY3Mpe3RhcmdldD0iX2JsYW5rIn0gIApbUmVncmVzc2lvbl0oaHR0cHM6Ly9saW5kZWxvZXYuZ2l0aHViLmlvL3Rlc3RzLWFzLWxpbmVhci8pe3RhcmdldD0iX2JsYW5rIn0gIApbRGlmZmVyZW50IHR5cGVzIG9mIHJlZ3Jlc3Npb25dKGh0dHBzOi8vd3d3LmFuYWx5dGljc3ZpZGh5YS5jb20vYmxvZy8yMDE1LzA4L2NvbXByZWhlbnNpdmUtZ3VpZGUtcmVncmVzc2lvbi8pe3RhcmdldD0iX2JsYW5rIn0gIApbT3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyBtZXRob2RdKGh0dHA6Ly9zZXRvc2EuaW8vZXYvb3JkaW5hcnktbGVhc3Qtc3F1YXJlcy1yZWdyZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltSZXNpZHVhbF0oaHR0cHM6Ly93d3cuc3RhdGlzdGljc2hvd3RvLmRhdGFzY2llbmNlY2VudHJhbC5jb20vcmVzaWR1YWwvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKCjx1PlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OiA8L3U+CgogUGFja2FnZSAgIHwgVXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhICAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEgIApbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgIApbc2tpbXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9za2ltci9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBnZXQgYW4gb3ZlcnZpZXcgb2YgZGF0YSAgIApbc3VtbWFyeXRvb2xzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2tpbXIvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIGRhdGEgaW4gYSBkaWZmZXJlbnQgc3R5bGUgICAKW3BkZnRvb2xzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGRmdG9vbHMvcGRmdG9vbHMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byByZWFkIGEgUERGIGludG8gUiAgIApbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byB1c2UgdGhlIGAlPD4lYCBwaXBwaW5nIG9wZXJhdG9yICAKW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBwZXJmb3JtIGZ1bmN0aW9ucyBvbiBhbGwgY29sdW1ucyBvZiBhIHRpYmJsZSAgIApbdGliYmxlXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgfCB0byBjcmVhdGUgZGF0YSBvYmplY3RzIHRoYXQgd2UgY2FuIG1hbmlwdWxhdGUgd2l0aCAgZHBseXIvc3RyaW5nci90aWR5ci9wdXJyciAgClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gc2VwYXJhdGUgZGF0YSB3aXRoaW4gYSBjb2x1bW4gaW50byBtdWx0aXBsZSBjb2x1bW5zIApbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSB2aXN1YWxpemF0aW9ucyB3aXRoIG11bHRpcGxlIGxheWVycyAgCgoKRG8gSSBuZWVkIHRvIHRhbGsgYWJvdXQgbWFjaGluZSBsZWFybmluZyBpbiBnZW5lcmFsIG1vcmUuLi4gY2xhc3NpZmljYXRpb24gdnMgcHJlZGljdGlvbj8=